환경 변수 누락 시 서버 기동 차단
목차
환경 변수 검증 강화 + CSRF allowedOrigins 조정 작업을 진행했다.
왜 이 시점에 건드렸나
보안 관련 작업은 "당장 뭔가 터졌을 때" 하게 되는 경우도 있지만, 이번 건은 조금 달랐다. 코드베이스를 훑다가 환경 변수 누락에 대한 런타임 에러 핸들링이 너무 느슨하다는 게 눈에 밟혔고, CSRF allowedOrigins도 명시적으로 잠가두지 않은 상태였다. 이런 류의 작업은 우선순위 경쟁에서 항상 밀린다. 기능 티켓, 버그 수정, 배포 일정 — 다 쳐내고 나면 "나중에 하자"로 미뤄지기 일쑤다. 근데 팀장 입장에서 이걸 계속 미루면 결국 내가 책임지는 사고로 돌아온다는 걸 알기 때문에, chore 레이블 달고 조용히 끼워 넣었다.
변경 파일별로 뭘 했는지
| 파일 | 역할 | 이번 변경 의미 |
|---|---|---|
.env.example |
환경 변수 템플릿 | 필수 시크릿 항목 명시, 누락 방지용 문서화 |
next.config.mjs |
Next.js 전역 설정 | CSRF allowedOrigins 목록 명시적 고정 |
src/instrumentation.ts |
앱 초기화 진입점 | 서버 기동 시 env 검증 훅 연결 |
src/lib/env-check.ts |
환경 변수 검증 모듈 | 필수값 누락/포맷 이상 시 early-exit 처리 |
env-check.ts가 이번 작업의 핵심이었다. 기존에는 코드 곳곳에서 process.env.SOMETHING ?? '' 식으로 그냥 빈 문자열 폴백을 쓰는 패턴이 흩어져 있었는데, 이걸 한 곳에 모아서 앱 기동 시점에 한 번에 검증하도록 바꿨다.
// src/lib/env-check.ts (패턴 예시)
const REQUIRED_SECRETS = [
'NEXTAUTH_SECRET',
'DATABASE_URL',
'INTERNAL_API_KEY',
] as const;
export function assertEnv() {
const missing: string[] = [];
for (const key of REQUIRED_SECRETS) {
const val = process.env[key];
if (!val || val.trim() === '') {
missing.push(key);
}
}
if (missing.length > 0) {
throw new Error(
`[env-check] 필수 환경 변수 누락: ${missing.join(', ')}\n` +
`.env.example 참고해서 채워주세요.`
);
}
}
instrumentation.ts에서 이 assertEnv()를 호출하게 연결해뒀다. Next.js의 instrumentation.ts는 서버 사이드 초기화 훅이라 여기서 터뜨리면 앱이 아예 뜨질 않는다 — 의도한 동작이다. 시크릿 없이 슬쩍 뜨는 것보다 확실하게 실패하는 게 낫다.
CSRF allowedOrigins — 왜 명시적으로 잠갔는지
Next.js의 CSRF 보호는 기본적으로 same-origin 요청에 대해 동작하는데, allowedOrigins를 따로 설정하지 않으면 환경에 따라 의도치 않은 범위가 열려 있을 수 있다. 특히 스테이징, 프리뷰 환경이 여럿 있는 경우엔 "어디서 요청이 들어와도 일단 통과" 같은 상황이 생기기도 한다.
// next.config.mjs (패턴 예시)
const nextConfig = {
experimental: {
serverActions: {
allowedOrigins: [
'localhost:3000',
process.env.NEXT_PUBLIC_APP_URL,
].filter(Boolean),
},
},
};
이렇게 명시해두면 allowedOrigins 외 출처에서 들어오는 Server Action 요청은 차단된다. 사소해 보이지만 멀티 도메인 환경에서 Cross-Origin 요청이 예상치 못하게 허용되는 걸 막는 기본 라인이다.
회고
이런 보안 관련 chore 작업을 팀에 설명할 때 항상 드는 고민이 있다. "이게 지금 당장 기능에 영향을 주는 것도 아닌데 왜 했어요?" — 이 질문에 대한 답을 PR 설명에 미리 써두는 습관이 생겼다. 코드 리뷰어 입장에서 맥락 없이 보안 설정 파일만 바뀌면 "이거 건드렸다가 뭔가 터지는 거 아냐?" 하고 불안해하는 경우가 있거든. 그래서 "env 누락 시 기동 실패 — 의도된 동작"이라는 걸 명확히 적어줬다.
env-check 패턴은 팀에 처음 도입할 때 약간의 마찰이 있었다. 로컬에서 .env.local을 제대로 안 채운 팀원이 앱이 뜨질 않아서 당황하는 케이스가 초기에 몇 번 있었다. 그래서 에러 메시지에 .env.example 참고해주세요 한 줄을 명시적으로 넣었더니 훨씬 나아졌다. 에러 메시지 하나가 생각보다 큰 일이다.
.env.example도 이번에 같이 정리했는데, 이게 의외로 온보딩에서 중요하다. 새 팀원이 처음 환경 셋업할 때 이 파일 보고 따라 하는 경우가 많기 때문에, 주석 없이 키만 나열돼 있으면 뭘 어디서 발급받아야 하는지 모른다. 이번에 각 키 옆에 짧게 용도/출처 주석을 달아뒀다.
보안 강화 작업은 "완성"이 없는 영역이라, 이번 PR은 그냥 한 스텝이다.
끝.
🛒 이 글과 어울리는 추천 상품
*위 링크는 쿠팡파트너스 활동의 일환이며, 일정액의 수수료를 제공받을 수 있습니다.
댓글 0
첫 댓글 달아줘.