프레임워크별
Next.js 보안 대책 — 프로덕션 하드닝 실무 레퍼런스
Next.js를 안전하게 운영하기 위한 실무 레퍼런스. 우선순위별 체크리스트에 더해 서버/클라이언트 경계와 환경 변수·의존성 CVE·Server Actions 인가·SSRF·헤더/CSP·레이트 제한을 자기 검증 체크리스트와 함께 다룹니다. 방어 중심, 공격 절차 없음.
대상: Next.js 앱을 운영하는 사람(App Router 상정). 여기서는 공격 절차를 다루지 않습니다 — 이 글은 하드닝을 위한 실무 레퍼런스입니다: 우선순위별 체크리스트, 영역별 지침, 자기 검증. 프레임워크 전반의 그림은 프레임워크별 보안 허브를 참조하세요.
우선순위별 하드닝 체크리스트
이 표를 위에서부터 실행하세요. P0가 전제, P1이 가장 잦은 사고의 원천, P2가 지속적인 운영 위생입니다.
P0 ── 전제 (먼저 할 것)
시크릿(API 키 등)을 브라우저에 노출하지 않기 / 의존성 CVE 모니터링 + 빠른 패치 / 견고한 프로덕션 설정
P1 ── 사고의 최대 원천
Server Actions/Route Handlers 인가 + 입력 검증 / 서버 fetch의 SSRF
P2 ── 운영 위생
헤더/CSP / 인증, 세션, 쿠키 / 레이트 제한
| 우선순위 | 통제 | 구체(Next.js) |
|---|---|---|
| P0 | 시크릿을 브라우저에 노출하지 않기 | NEXT_PUBLIC_은 브라우저에 안전한 값에만. 시크릿은 Server Component/Action/Route Handler 안에서만 |
| P0 | 의존성 CVE | npm audit/osv-scanner로 모니터링. 가동 버전으로 판단하고 빠르게 패치. 본체 RCE에 추종 |
| P0 | 프로덕션 설정 | 프로덕션 빌드로 구동. 오류로 내부(스택/환경 변수)를 흘리지 않음 |
| P1 | 액션 인가 | 모든 Server Action/Route Handler에 인증 + 소유자 스코프 인가 |
| P1 | 입력 검증 | 입력을 스키마 검증(형/범위/허용값). 클라이언트를 신뢰하지 않음 |
| P1 | SSRF 방어 | 서버 측 URL 취득을 허용 목록으로 제한 + 내부 IP/메타데이터 차단. 이미지 리모트 패턴을 제한 |
| P2 | 헤더/CSP | next.config에 보안 헤더 + HSTS. App Router에서 nonce 기반 CSP 검토 |
| P2 | 인증/쿠키 | 세션 쿠키에 Secure/HttpOnly/SameSite. 인가를 미들웨어에만 맡기지 않음 |
| P2 | 레이트 제한 | 인증, Server Actions, Route Handlers에 제한 |
1. 서버/클라이언트 경계와 환경 변수(P0)
Next.js 최대의 사고 원천은 서버 전용이어야 할 시크릿이 클라이언트로 흘러 들어가는 것입니다.
- 브라우저에 안전한 값에만
NEXT_PUBLIC_을 붙인다. API 키나 접속 정보에는 절대 붙이지 않는다(NEXT_PUBLIC_값은 빌드 시점에 클라이언트 번들에 구워 넣어져 방문자에게 보인다). - 시크릿은 Server Component / Server Actions / Route Handlers 안에서만 읽고,
props와 응답(직렬화되는 값)에 섞지 않는다. - 서버 전용 모듈이 클라이언트에 import되지 않도록 유지한다(실수로 포함되면 시크릿이 번들될 수 있음). .env 파일과 시크릿을 참조하세요.
2. 의존성 CVE와 본체(P0)
- 의존성(npm) CVE를 기계 모니터링한다(
npm audit이나 osv-scanner로). 가동 중인 버전으로 판단하고 빠르게 패치한다(package.json 선언이 아니라 실제로 설치된 것으로 판단). - Next.js 본체는 심각한 RCE가 있었으므로, 공개되면 빠르게 추종한다. 운영 규율은 CVE에 뒤처지지 않기, 실무는 취약점 대응 플레이북을 참조.
- Node/Next를 지원 버전으로 유지하고 EOL 버전을 방치하지 않는다.
3. Server Actions / Route Handlers(인가 + 검증, P1)
이들은 공개된 서버 진입점입니다. 호출할 수 있다고 해서 허용된 것은 아닙니다.
흔함(위험)
- 액션을 "로그인 = 허용"으로 취급
- 미들웨어 인증에만 의존하고 소유자 검사가 없음
- 입력을 검증하지 않고 DB나 외부 호출로 넘김
- 클라이언트가 제공한 값(ID, 플래그)을 그대로 신뢰
올바름
- 인증에 더해 모든 액션/핸들러에서 소유자/권한 스코프 인가
- 미들웨어에 맡기지 않는다(데이터에 가까운 곳에서 인가)
- 입력을 스키마 검증(형/범위/허용값)
- ID 교체가 통하지 않도록 서버에서 재검증
IDOR란을 참조하세요. 모든 조회/갱신/삭제 경로에서 소유자 검사를 합니다.
4. SSRF와 서버 측 fetch(P1)
서버 측에서 사용자가 제공한 URL을 가져오는 처리(이미지 프록시, 웹훅, 메타데이터 취득)는 SSRF의 입구입니다.
- 취득 대상을 허용 목록으로 제한하고, 접속 시점에 프라이빗 IP와 클라우드 메타데이터(169.254.169.254)에 도달하는 것을 차단한다.
- 이미지 최적화의 리모트 패턴을 최소한으로 유지한다(임의 호스트의 취득을 허용하지 않음).
- SSRF란을 참조하세요. 본 사이트는 외부 fetch를 SSRF 안전 게이트웨이를 통해 보냅니다.
5. 인젝션과 출력
- XSS: React는 기본적으로 출력을 이스케이프한다.
dangerouslySetInnerHTML에 사용자 입력을 넘기지 않는다(정말 필요하면 새니타이즈한 뒤에만). XSS란을 참조하세요. - SQL/인젝션: ORM/플레이스홀더로 바인딩하고, 문자열 연결로 쿼리를 만들지 않는다(→ SQL 인젝션이란).
eval같은 위험한 평가에 외부 입력을 넘기지 않는다.
6. 보안 헤더와 CSP(P2)
next.config에 보안 헤더(X-Content-Type-Options 등)와 HSTS를 설정한다. 자기 사이트는 보안 헤더 진단으로 확인.- App Router에서는 nonce 기반 CSP를 검토한다(인라인 스크립트의 무제한 허용을 피한다). 분석/광고 태그와의 공존에는 설계가 필요하다는 점에 유의.
7. 인증, 세션, 쿠키(P2)
- 세션 쿠키에 Secure / HttpOnly / SameSite를 설정한다.
- 인가를 미들웨어 인증에만 위임하지 않는다 — 미들웨어는 보완이고, 실제 판단은 액션/핸들러/데이터 계층에서 확인한다(경로에 따라 미들웨어를 우회할 수 있음).
- 로그인 시 세션을 적절히 재생성하고 만료시킨다.
8. 레이트 제한(P2)
- 인증, Server Actions, Route Handlers에 시도/처리량 제한을 걸어 무차별 대입, 남용, DoS를 억제한다.
검증: 당신의 Next.js는 실제로 하드닝되어 있는가
만드는 것으로 끝이 아니라 점검해야 비로소 완료입니다. 아래는 자기 사이트/환경에 대한 방어적 자기 점검입니다.
시크릿이 클라이언트로 새지 않는다
NEXT_PUBLIC_을 붙이지 않았는지 확인.프로덕션이 오류로 내부를 흘리지 않는다
액션 인가가 유지된다
헤더, 의존성, SSRF
npm audit/osv가 깨끗한지, 외부 fetch가 내부 IP에 도달할 수 없는지 확인.본 사이트의 관점: 본체가 아니라 '경계와 의존성'을 관리하라
본 사이트는 Next.js로 구동되며, 무게중심은 화려한 설정이 아니라 서버/클라이언트 경계와 의존성 신선도에 있습니다. 시크릿은 서버에 남기고, 공개 진입점(Server Actions/Route Handlers)에는 항상 인가와 입력 검증을 두며, 의존성은 매 배포 전에 CVE 감사를 받습니다. 본 사이트의 출발점 자체가 "방치된 CVE의 자동 악용" 사고였으므로, 의존성 기계 모니터링은 최우선 습관입니다. 외부 URL fetch는 SSRF 안전 게이트웨이를 통과해 내부 IP나 메타데이터에 도달할 수 없게 합니다.
다음에 읽기
- 허브: 프레임워크별 보안 · Laravel 보안
- 의존성: CVE에 뒤처지지 않기 · 취약점 대응 플레이북
- 용어: IDOR란 · SSRF란 · .env 파일과 시크릿 · XSS
- 도구: 보안 헤더 진단
FAQ
QNext.js를 지키려면 무엇부터 해야 하나요?
P0 세 가지입니다. (1) 시크릿(API 키 등)을 브라우저에 노출하지 않습니다(브라우저에 안전한 값에만 NEXT_PUBLIC_을 붙이고, API 키나 접속 정보에는 절대 붙이지 않음). (2) 의존성 CVE를 기계 모니터링하고, 가동 중인 버전으로 판단하며, 빠르게 패치합니다(본체 RCE 포함). (3) 프로덕션 설정을 다집니다(프로덕션 빌드로 구동, 오류로 내부를 흘리지 않음). 다음으로 Server Actions / Route Handlers의 인가와 입력 검증, SSRF 방어로 넘어갑니다.
Q환경 변수는 어떻게 안전하게 다루나요?
원칙은 '시크릿은 서버에 남긴다'입니다. 브라우저에 안전한 값에만 NEXT_PUBLIC_을 붙이고, API 키나 접속 정보에는 절대 붙이지 않습니다(NEXT_PUBLIC_ 값은 빌드 시점에 클라이언트 번들에 구워 넣어져 방문자에게 보입니다). 시크릿은 서버 컴포넌트 / Server Actions / Route Handlers 안에서만 읽고, props나 응답에 섞여 들어가지 않도록 설계합니다.
QServer Actions에서 무엇을 주의해야 하나요?
Server Actions와 Route Handlers는 공개된 서버 진입점입니다. 호출할 수 있다고 해서 허용된 것은 아닙니다. 로그인(인증) 위에, 모든 작업을 소유자로 스코프하는 인가를 작성하고, 입력은 항상 검증합니다(예: 스키마 검증). 미들웨어 인증에만 의존하지 말고, 액션/핸들러 안에서도 소유자 검사를 합니다.
QSSRF에는 어떻게 대비하나요?
주된 입구는 서버 측에서 사용자가 제공한 URL을 가져오는 처리(이미지 프록시, 웹훅, 메타데이터 취득)입니다. 취득 대상을 허용 목록으로 제한하고, 접속 시점에 프라이빗 IP와 클라우드 메타데이터(169.254.169.254)에 도달하는 것을 차단합니다. 이미지 최적화의 리모트 패턴도 최소한으로 유지합니다. 자세한 내용은 용어 페이지를 참조하세요.
Qnpm 의존성 취약점은 어떻게 관리하나요?
npm audit이나 osv-scanner로 알려진 CVE를 기계 모니터링하고, 가동 중인 버전으로 판단하며, 빠르게 패치합니다(package.json의 선언이 아니라 실제로 설치된 것으로 판단). Next.js 본체는 심각한 RCE가 있었으므로 빠른 추종이 중요합니다. 또한 Node/Next를 지원 버전으로 유지하고 EOL 버전을 방치하지 않습니다.