프레임워크별
Next.js 보안 대책 — Server Actions·환경 변수·의존성 CVE의 방어법
Next.js는 기본값이 안전한 편이지만, 사고는 '서버와 클라이언트의 경계'에서 일어납니다. 3대 = 환경 변수의 노출(서버 전용 시크릿을 클라이언트로)·Server Actions/Route Handlers의 인가 누락·의존성 패키지의 알려진 CVE(본체 RCE 포함). 경계를 의식해 시크릿을 서버 한정으로·소유자 검사·CVE 모니터링으로 지키는 법을, 공격 절차는 빼고 풀어냅니다.
대상: Next.js로 앱을 운영하는 사람. 여기서는 공격 절차를 다루지 않고, 서버와 클라이언트의 경계에서 일어나는 사고와 그 막는 법을 풀어냅니다. 전체 그림은 프레임워크별 보안 입구도 참고하세요.
3대 함정(경계에서 일어난다)
Next.js의 이스케이프나 라우팅은 우수하지만, 다음 세 가지는 개발자가 경계를 의식해 막는 영역입니다.
① 환경 변수의 노출
NEXT_PUBLIC_의 오용이나, 시크릿을 클라이언트로 넘김. 번들에 구워 넣어져 방문자에게 보인다.
② 액션의 인가 누락
Server Actions / Route Handlers에 소유자 검사 없음. ID를 바꿔 타인의 데이터를 조작.
③ 의존성의 알려진 CVE
본체·의존성의 알려진 취약점(RCE 포함)을 방치. 가동 중인 버전으로 판단하고 즉시 패치.
막는 법(3단계)
시크릿은 서버 한정으로
NEXT_PUBLIC_을 붙이고, API 키·접속 정보 같은 시크릿에는 붙이지 마세요. 시크릿은 서버 컴포넌트 / Server Actions / Route Handler 안에서만 읽고, props나 응답에 섞지 마세요. (→ .env와 시크릿 정보)Server Actions / Route Handlers에서 인가를 매번 확인
의존성 CVE를 기계 모니터링해 즉시 패치
흔히 하는(위험)
- 시크릿에
NEXT_PUBLIC_을 붙여 클라이언트에 노출 - Server Actions를 「로그인해 있으면 실행 가능」으로
- 외부 URL 가져오기를 서버에서 무방비로(SSRF)
- 의존성의 알려진 CVE를 방치
올바른
- 시크릿은 서버 한정·클라이언트로 넘기지 않음
- 액션에서 소유자 스코프의 인가
- URL 가져오기는 SSRF 대책(내부 IP 차단·허용 대상 한정)
- 의존성 CVE를 기계 모니터링 + 즉시 패치
본 사이트의 관점: 본체보다 '경계와 의존성'을 관리한다
본 사이트는 Next.js로 돌아가고 있으며, 실제로 방어의 무게 중심을 두는 것은 화려한 설정이 아니라 「서버/클라이언트의 경계」와 「의존성의 신선도」입니다. 시크릿은 반드시 서버 측에 두고, 공개 입구(Server Actions / Route Handlers)에는 인가를 반드시 쓰며, 의존성은 매 배포 전에 CVE 감사합니다. 본 사이트의 출발점 자체가 "방치된 CVE의 자동 악용"이라는 사고였기에, 의존성의 기계 모니터링은 최우선 습관입니다. 외부 URL을 가져오는 처리는 자체 SSRF 안전 게이트웨이를 통과시켜, 내부 IP나 메타데이터에 도달하지 못하게 합니다(→ SSRF란 무엇인가).
다음으로 읽기
- 입구: 프레임워크별 보안(입구) · Laravel 보안 대책
- 의존성: CVE에 뒤처지지 않는 시스템 · 취약점(CVE) 대응 실무
- 용어: IDOR이란 무엇인가 · SSRF란 무엇인가 · .env와 시크릿 정보
FAQ
QNext.js는 안전한 프레임워크인가요?
Next.js는 출력 이스케이프 등 안전한 기본값을 갖추고 있어, 기본 상태에서는 비교적 견고합니다. 다만 사고는 본체의 기본값이 아니라 '서버와 클라이언트의 경계'를 다루는 방식에서 일어납니다. 서버 전용이어야 할 시크릿이 클라이언트에 실려 버리거나, Server Actions에 인가를 쓰는 것을 잊거나, 의존성 패키지의 알려진 CVE를 방치하는 것 — 이 세 가지가 실운영의 주된 구멍입니다. 기본값에만 기대지 말고, 경계와 의존성을 스스로 관리해야 합니다.
Q환경 변수는 어떻게 다뤄야 안전한가요?
원칙은 '시크릿은 서버에만'입니다. 브라우저에 실어도 되는 값에만 NEXT_PUBLIC_을 붙이고, API 키나 접속 정보 같은 시크릿에는 절대 붙이지 마세요(NEXT_PUBLIC_은 빌드 시 클라이언트 번들에 구워 넣어져 방문자에게 보입니다). 시크릿은 서버 컴포넌트 / Server Actions / Route Handler 안에서만 읽고, props나 응답에 섞이지 않도록 설계합니다.
QServer Actions에서 주의할 점은 무엇인가요?
Server Actions와 Route Handlers는 '공개된 서버의 입구'입니다. 호출할 수 있다 = 실행해도 된다,가 아닙니다. 로그인(인증)에 더해, 그 조작 대상이 정말 그 사용자의 것인지를 매번 스코프하는 인가를 쓰세요. 인가를 잊으면 ID를 바꾸는 것만으로 타인의 데이터를 갱신·삭제할 수 있습니다(인증≠인가). 입력 검증과 함께, 액션 측에서 반드시 소유자 검사를 하세요.