웹 개발
NEXT_PUBLIC_를 붙인 환경 변수가 브라우저에 보였던 날
Next.js 환경 변수에 NEXT_PUBLIC_ 접두사를 붙이면 무엇이 달라지는지, 배포 전 확인 순서와 함께 정리했습니다.
시작은 결제 키를 옮기는 작업이었다
결제 테스트 화면에서 서버 환경 변수를 읽고 싶었다. PAYMENT_SECRET 앞에 NEXT_PUBLIC_를 붙이자 화면은 정상 동작했다. 그런데 배포 후 브라우저가 받은 JavaScript에서 테스트 키 문자열을 검색할 수 있었다.
이 접두사는 단순한 접근 허용 표시가 아니다. 빌드 때 값을 브라우저 번들에 넣으라는 뜻이다. 이름에 public이 들어간 이유를 그때 정확히 이해했다.
공개 값과 비밀 값을 나눈 기준
사용자가 페이지를 열었을 때 알아도 괜찮은 값만 NEXT_PUBLIC_으로 시작하게 했다. 공개 API URL이나 지도 서비스 식별자는 가능하지만, DB URL·관리자 토큰·결제 secret은 서버 전용이다.
클라이언트가 결제를 시작해야 할 때도 비밀을 보내지 않는다. 필요한 주문 ID만 서버 Route Handler로 보내고, 서버가 비밀 키로 외부 API를 호출한다.
export async function POST(request: Request) {
const { orderId } = await request.json()
const response = await fetch('https://payment.example/charge', {
method: 'POST',
headers: { Authorization: `Bearer ${process.env.PAYMENT_SECRET}` },
body: JSON.stringify({ orderId }),
})
return Response.json(await response.json())
}
소스가 아니라 결과물을 확인했다
.env가 Git에 없다고 안전한 것은 아니다. 번들에 들어갔는지를 직접 봤다.
npm run build
rg 'sk_test_' .next
문자열이 나오면 이미 공개된 값으로 취급한다. 저장소에서 지우는 데서 끝내지 않고 해당 키를 폐기하고 새 키로 바꿨다.
배포 전 확인 목록
NEXT_PUBLIC_값이 화면에 보여도 되는가?- 비밀 값이 Client Component에서 참조되지 않는가?
- CI의 변수 이름도 같은가?
- 노출 가능성이 있었던 키를 교체했는가?
접두사 하나가 배포물의 공개 범위를 바꾼다. 이름을 붙이기 전에 “사용자가 이 값을 읽어도 되는가”를 묻는 습관이 가장 간단한 방어였다.