프레임워크별
ASP.NET Core 보안 — 프로덕션 하드닝 실무 레퍼런스
ASP.NET Core 프로덕션 하드닝 실무 레퍼런스. 우선순위 체크리스트에 더해 프로덕션 오류·시크릿(User Secrets/Key Vault)·NuGet CVE·인가·over-posting·역직렬화·SSRF까지. 방어 중심, 공격 절차 없음.
대상: ASP.NET Core로 앱이나 API를 운영하는 사람. 여기서는 공격 절차를 다루지 않고, 프로덕션을 굳히기 위한 실무 레퍼런스(우선순위 체크리스트·영역별 대책·자기 검증)를 제시합니다. 프레임워크 전체의 관점은 프레임워크별 보안의 입구도 참조하세요.
우선순위 하드닝 체크리스트
먼저 이 표를 위에서부터 실시합니다. P0은 전제, P1이 가장 빈번한 사고원, P2는 지속적인 운영 위생입니다.
P0 ── 전제(먼저 이것)
프로덕션에서 상세 오류 비표시 / 시크릿을 외부화 / NuGet 의존성 CVE 즉시 패치
P1 ── 가장 빈번한 사고원
인가([Authorize]·기본 거부·소유자) / over-posting 대책(DTO/[Bind])
P2 ── 운영 위생
안전하지 않은 역직렬화 / HTTPS·헤더·antiforgery / SSRF
| 우선순위 | 대책 | 구체(ASP.NET Core) |
|---|---|---|
| P0 | 프로덕션 오류 | UseExceptionHandler. Developer Exception Page/상세를 프로덕션에서 내보내지 않기(환경 판정을 올바르게) |
| P0 | 시크릿 외부화 | appsettings.json에 직접 기재하지 않기. 개발=User Secrets, 프로덕션=환경/Key Vault |
| P0 | NuGet 의존성 CVE | dotnet list package --vulnerable/osv-scanner로 모니터링·실가동 버전으로 판정해 즉시 패치 |
| P1 | 인가를 명시 | [Authorize]+기본 거부(폴백 정책)+리소스 기반/소유자 확인 |
| P1 | over-posting 대책 | 엔티티 직접 바인딩을 피하고 DTO로. [Bind]로 받아들일 필드를 한정 |
| P2 | 역직렬화 | BinaryFormatter를 쓰지 않기. 신뢰할 수 없는 데이터를 안전하지 않은 형식으로 복원하지 않기 |
| P2 | HTTPS/헤더/CSRF | UseHttpsRedirection·UseHsts·antiforgery(CSRF)·Cookie 속성 |
| P2 | SSRF | 서버 측 취득은 허용 리스트로 한정+내부 IP/메타데이터 차단 |
1. 프로덕션 오류의 노출 방지 (P0)
- 프로덕션에서는
UseExceptionHandler등으로 범용 오류로 전환하고, Developer Exception Page/상세를 내보내지 않습니다(ASPNETCORE_ENVIRONMENT=Production등의 환경 판정을 올바르게). - 스택 트레이스나 내부 구조를 외부에 내보내지 않습니다.
2. 시크릿의 외부화 (P0)
- 연결 문자열이나 키를 appsettings.json에 직접 기재하지 않습니다. 개발은 User Secrets, 프로덕션은 **환경 변수나 클라우드의 시크릿 관리(Key Vault)**에서 읽어 들입니다.
- appsettings.json은 실수 커밋/공개로 누출되기 쉽습니다. 리포지토리에 커밋하지 않고, 공개 디렉터리에 두지 않습니다(→ 공개 디렉터리에 시크릿을 두지 않기). 만일 누출되면 신속히 로테이션합니다.
3. NuGet 의존성의 CVE (P0)
dotnet list package --vulnerable나 osv-scanner로 알려진 CVE를 기계 모니터링하고, 실가동 버전으로 판정해 즉시 패치합니다(→ 의존성 CVE 모니터링 · 취약점 대응 실무).- .NET을 지원 대상 버전으로 유지하고, EOL 버전을 방치하지 않습니다.
4. 인가 (P1 — 가장 빈번한 사고원)
자주 하는(위험한)
- 엔드포인트에
[Authorize]를 붙이는 것을 잊음 - 인증은 있지만 소유자 확인이 없음
- 기본값이 "허용" 쪽이고 미인증이 그대로 통과
- 역할/정책 설계 없이 산발적으로 판정
올바른
[Authorize]+폴백 정책으로 기본 거부- 역할/정책 기반+리소스 기반 인가로 소유자 확인
- 취득·갱신·삭제의 모든 경로에서 확인
- 인가는 명시적으로 구성하고, 기본값에 맡기지 않기
용어는 IDOR란. 인증과 인가는 별개이며, 인가는 데이터에 가까운 곳에서 확인합니다.
5. over-posting (P1)
- 엔티티를 직접 바인딩하지 않습니다. 입력 전용 DTO에 바인딩하고, 필요한 필드만 받아들입니다.
- 또는 **
[Bind]**로 받아들일 필드를 명시적으로 한정합니다. 권한 플래그 등을 외부 입력에서 덮어쓰게 하지 않습니다.
6. 안전하지 않은 역직렬화와 입력 (P2)
BinaryFormatter를 쓰지 않습니다(비권장/위험). 신뢰할 수 없는 데이터를 안전하지 않은 형식으로 복원하지 않습니다(조건에 따라 RCE로 이어질 수 있음)(→ RCE란).- 입력은 **모델 검증(데이터 주석 등)**으로 형·범위·허용값을 검증한 뒤에 사용합니다.
7. HTTPS·헤더·antiforgery (P2)
UseHttpsRedirection+**UseHsts**로 HTTPS를 강제하고, Cookie를 secure/httponly/samesite로 표시합니다.- 폼/상태 변경 요청에는 **antiforgery 토큰(CSRF 대책)**을 사용합니다(→ CSRF란).
- 보안 헤더를 부여합니다(본 사이트는 보안 헤더 진단으로 확인).
8. SSRF와 서버 측 취득 (P2)
- 서버(
HttpClient등)가 사용자 지정 URL을 취득하는 처리는 허용 리스트로 대상을 한정하고, 내부 IP/메타데이터로의 도달을 차단합니다(→ SSRF란). 업로드는 검증하고 공개면 밖에 저장합니다.
검증: 내 ASP.NET Core는 정말 굳혀졌는가
만들면 끝이 아니라, 점검해야 비로소 완료입니다. 다음은 자신의 환경에 대한 방어적 자기 점검입니다.
프로덕션에서 Developer Exception Page가 나오지 않는가
시크릿이 설정/리포지토리에 없는가
appsettings.json에 연결 문자열/키가 직접 기재되지 않았는지, 리포지토리에 시크릿이 포함되지 않았는지 확인.인가가 작동하는가
의존성과 HTTPS/헤더
dotnet list package --vulnerable/osv가 클린인지, 헤더 진단으로 HTTPS/HSTS 등이 붙는지 확인.본 사이트의 관점: 견고한 기반이라도 '설정과 인가'는 자신의 책임
ASP.NET Core는 인증·인가·데이터 보호의 구조가 갖추어져 있지만, 프로덕션의 설정과 인가의 부여만은, 환경별·엔드포인트별로 자신이 올바르게 결정해야 합니다. 본 사이트는 다른 스택이지만 원칙은 같습니다 — 프로덕션에서 내부 정보를 내보내지 않고, 시크릿을 설정의 외부에 두고, 공개 입구에는 반드시 인가를 작성하고, 의존성은 CVE 모니터링한다. 견고한 기반의 가치는, 올바른 설정과 명시적인 인가가 있어야 비로소 발휘됩니다.
다음으로 읽기
- 입구: 프레임워크별 보안(입구) · Spring Boot 보안(같은 기업 계열·의존성/인가의 형태가 가깝다)
- 실무: 취약점 대응 실무 · 의존성 CVE 모니터링 · 공개 디렉터리에 시크릿을 두지 않기
- 용어: IDOR란 · RCE란 · CSRF · SSRF
- 도구: 보안 헤더 진단
FAQ
QASP.NET Core 보안, 무엇부터 해야 하나요?
우선순위 P0의 3가지입니다. (1) 프로덕션에서 Developer Exception Page/상세 오류를 내보내지 않기(UseExceptionHandler·환경 판정을 올바르게), (2) 시크릿을 appsettings.json에 직접 기재하지 말고 외부화하기(개발은 User Secrets, 프로덕션은 환경 변수나 Key Vault), (3) NuGet 의존성의 CVE를 기계 모니터링하고 실가동 버전으로 판정해 즉시 패치. 다음으로 인가([Authorize]·기본 거부)와 over-posting 대책으로 넘어갑니다.
Q시크릿(연결 문자열이나 API 키)은 어디에 두어야 하나요?
원칙은 appsettings.json에 직접 기재하지 않는 것입니다. 개발에서는 User Secrets, 프로덕션에서는 환경 변수나 클라우드의 시크릿 관리(Key Vault)에서 읽어 들입니다. appsettings.json은 리포지토리에 들어가기 쉽고, 공개 디렉터리나 실수 커밋으로 누출되기 쉽기 때문입니다. 만일 누출되면 연결 문자열이나 키를 신속히 로테이션하세요.
Q인가 속성의 부착 누락은 어떻게 막나요?
컨트롤러나 엔드포인트에 [Authorize]를 붙이는 것을 잊으면, 인증을 거치지 않고 누구나 도달할 수 있게 됩니다. 기본값을 '거부' 쪽으로 기울이고(미인증을 튕겨내는 폴백 정책), 역할/정책 기반 인가로 권한을 명시하고, 리소스 소유자 확인(리소스 기반 인가)을 작성합니다. '로그인해 있으면 실행 가능'에서 멈추지 말고, 조작 대상의 소유자까지 확인하세요.
Qover-posting이란 무엇인가요?
모델 바인딩이 모든 필드를 엔티티에 받아들이면, 사용자가 보낸 예상 밖 필드(권한 플래그 등)까지 덮어써질 수 있습니다 — 그것이 over-posting입니다. 대책은, 입력 전용 DTO에 바인딩하거나, [Bind]로 받아들일 필드를 명시적으로 한정하는 것입니다. 엔티티를 직접 바인딩하지 마세요.
Q안전하지 않은 역직렬화는 왜 위험한가요?
BinaryFormatter 같은 안전하지 않은 역직렬화기로 신뢰할 수 없는 데이터를 복원하면, 조건에 따라 원격 코드 실행(RCE)으로 이어질 수 있습니다. BinaryFormatter는 비권장/위험으로 간주되니 사용하지 마세요. 외부 유래 데이터는 출처를 검증하고, 필요하면 안전한 형식(예: 적절히 설정한 JSON)으로 한정합니다.