본문으로 건너뛰기
>_ITDITD웹 보안 플랫폼

프레임워크별

Next.js 보안 대책 — Server Actions·환경 변수·의존성 CVE의 방어법

Next.js는 기본값이 안전한 편이지만, 사고는 '서버와 클라이언트의 경계'에서 일어납니다. 3대 = 환경 변수의 노출(서버 전용 시크릿을 클라이언트로)·Server Actions/Route Handlers의 인가 누락·의존성 패키지의 알려진 CVE(본체 RCE 포함). 경계를 의식해 시크릿을 서버 한정으로·소유자 검사·CVE 모니터링으로 지키는 법을, 공격 절차는 빼고 풀어냅니다.

게시 2026-07-02 업데이트 2026-07-02 3분 읽기

대상: Next.js로 앱을 운영하는 사람. 여기서는 공격 절차를 다루지 않고, 서버와 클라이언트의 경계에서 일어나는 사고와 그 막는 법을 풀어냅니다. 전체 그림은 프레임워크별 보안 입구도 참고하세요.

3대 함정(경계에서 일어난다)

Next.js의 이스케이프나 라우팅은 우수하지만, 다음 세 가지는 개발자가 경계를 의식해 막는 영역입니다.

① 환경 변수의 노출

NEXT_PUBLIC_의 오용이나, 시크릿을 클라이언트로 넘김. 번들에 구워 넣어져 방문자에게 보인다.

② 액션의 인가 누락

Server Actions / Route Handlers에 소유자 검사 없음. ID를 바꿔 타인의 데이터를 조작.

③ 의존성의 알려진 CVE

본체·의존성의 알려진 취약점(RCE 포함)을 방치. 가동 중인 버전으로 판단하고 즉시 패치.

Next.js에서 일어나기 쉬운 3대 사고. 모두 '서버/클라이언트의 경계'가 관련된다.

막는 법(3단계)

1

시크릿은 서버 한정으로

브라우저에 실어도 되는 값에만 NEXT_PUBLIC_을 붙이고, API 키·접속 정보 같은 시크릿에는 붙이지 마세요. 시크릿은 서버 컴포넌트 / Server Actions / Route Handler 안에서만 읽고, props나 응답에 섞지 마세요. (→ .env와 시크릿 정보)
2

Server Actions / Route Handlers에서 인가를 매번 확인

이것들은 공개된 서버의 입구입니다. 로그인(인증)에 더해, 대상이 정말 그 사용자의 것인지를 매번 스코프하세요. 잊으면 ID를 바꿔 타인의 데이터가 조작될 수 있습니다(→ IDOR이란 무엇인가). 입력 검증도 액션 측에서 하세요.
3

의존성 CVE를 기계 모니터링해 즉시 패치

본체·의존성의 알려진 취약점은 「가동 중인 버전」으로 판단하고(package.json의 하한은 거짓말한다), 기계 모니터링으로 조기에 탐지해 즉시 패치하세요. 발단은 방치된 CVE의 자동 악용이 많습니다. (→ CVE에 뒤처지지 않는 시스템)

흔히 하는(위험)

  • 시크릿에 NEXT_PUBLIC_을 붙여 클라이언트에 노출
  • Server Actions를 「로그인해 있으면 실행 가능」으로
  • 외부 URL 가져오기를 서버에서 무방비로(SSRF)
  • 의존성의 알려진 CVE를 방치

올바른

  • 시크릿은 서버 한정·클라이언트로 넘기지 않음
  • 액션에서 소유자 스코프의 인가
  • URL 가져오기는 SSRF 대책(내부 IP 차단·허용 대상 한정)
  • 의존성 CVE를 기계 모니터링 + 즉시 패치

본 사이트의 관점: 본체보다 '경계와 의존성'을 관리한다

본 사이트는 Next.js로 돌아가고 있으며, 실제로 방어의 무게 중심을 두는 것은 화려한 설정이 아니라 「서버/클라이언트의 경계」와 「의존성의 신선도」입니다. 시크릿은 반드시 서버 측에 두고, 공개 입구(Server Actions / Route Handlers)에는 인가를 반드시 쓰며, 의존성은 매 배포 전에 CVE 감사합니다. 본 사이트의 출발점 자체가 "방치된 CVE의 자동 악용"이라는 사고였기에, 의존성의 기계 모니터링은 최우선 습관입니다. 외부 URL을 가져오는 처리는 자체 SSRF 안전 게이트웨이를 통과시켜, 내부 IP나 메타데이터에 도달하지 못하게 합니다(→ SSRF란 무엇인가).

다음으로 읽기

FAQ

QNext.js는 안전한 프레임워크인가요?
A

Next.js는 출력 이스케이프 등 안전한 기본값을 갖추고 있어, 기본 상태에서는 비교적 견고합니다. 다만 사고는 본체의 기본값이 아니라 '서버와 클라이언트의 경계'를 다루는 방식에서 일어납니다. 서버 전용이어야 할 시크릿이 클라이언트에 실려 버리거나, Server Actions에 인가를 쓰는 것을 잊거나, 의존성 패키지의 알려진 CVE를 방치하는 것 — 이 세 가지가 실운영의 주된 구멍입니다. 기본값에만 기대지 말고, 경계와 의존성을 스스로 관리해야 합니다.

Q환경 변수는 어떻게 다뤄야 안전한가요?
A

원칙은 '시크릿은 서버에만'입니다. 브라우저에 실어도 되는 값에만 NEXT_PUBLIC_을 붙이고, API 키나 접속 정보 같은 시크릿에는 절대 붙이지 마세요(NEXT_PUBLIC_은 빌드 시 클라이언트 번들에 구워 넣어져 방문자에게 보입니다). 시크릿은 서버 컴포넌트 / Server Actions / Route Handler 안에서만 읽고, props나 응답에 섞이지 않도록 설계합니다.

QServer Actions에서 주의할 점은 무엇인가요?
A

Server Actions와 Route Handlers는 '공개된 서버의 입구'입니다. 호출할 수 있다 = 실행해도 된다,가 아닙니다. 로그인(인증)에 더해, 그 조작 대상이 정말 그 사용자의 것인지를 매번 스코프하는 인가를 쓰세요. 인가를 잊으면 ID를 바꾸는 것만으로 타인의 데이터를 갱신·삭제할 수 있습니다(인증≠인가). 입력 검증과 함께, 액션 측에서 반드시 소유자 검사를 하세요.