Vercel 환경변수 보안 체크리스트: NEXT_PUBLIC·VITE 키 노출 10가지
Vercel 대시보드의 Environment Variables에 값을 넣었다고 모든 키가 서버 안에만 남는 것은 아닙니다. Next.js의 NEXT_PUBLIC_, Vite의 VITE_처럼 클라이언트 공개를 뜻하는 접두사를 사용하면 값이 빌드된 자바스크립트에 포함됩니다. 서버 변수도 API 응답, 오류 메시지나 로그에 출력하면 다시 노출될 수 있습니다.
1. 공개 설정과 비밀 자격 증명을 분류했는가
분석 도구 ID, 공개 사이트 URL처럼 브라우저가 동작하려면 알아야 하는 값은 공개 설정입니다. 데이터베이스 비밀번호, Supabase service_role, Stripe secret key, 이메일 발송 토큰, 관리자 API 토큰은 비밀 자격 증명입니다. “API 키”라는 이름만 보고 공개·비공개를 판단하지 말고, 그 키로 읽기·쓰기·결제·관리 작업을 수행할 수 있는지 권한을 기준으로 구분하세요.
| 값의 예 | 브라우저 공개 | 권장 위치 |
|---|---|---|
| 사이트 URL·분석 측정 ID | 의도적으로 가능 | 공개 환경변수 또는 정적 설정 |
| Supabase anon/publishable key | RLS 전제에서 가능 | 클라이언트, 단 권한은 데이터 정책으로 제한 |
| Supabase service role·DB 비밀번호 | 절대 금지 | 서버 함수의 비밀 환경변수 |
| Stripe publishable key | 가능 | 클라이언트 |
| Stripe secret·webhook secret | 절대 금지 | 서버 API·웹훅 함수 |
2. NEXT_PUBLIC_ 변수에 비밀을 넣지 않았는가
Next.js 공식 문서는 NEXT_PUBLIC_ 접두사가 붙은 값을 빌드 시 브라우저용 자바스크립트에 인라인한다고 설명합니다. 대시보드에서 값을 숨겨도 최종 번들에는 실제 문자열이 들어갈 수 있습니다. 서버 전용 키는 접두사 없이 두고 Server Component, Route Handler, API Route처럼 서버에서만 실행되는 코드에서 읽으세요.
next.config.js의 env 항목도 주의해야 합니다. Next.js 문서에 따르면 이 방식으로 지정한 값은 접두사와 관계없이 자바스크립트 번들에 포함될 수 있습니다. 비밀키를 편의를 위해 설정 파일에 전달하지 마세요.
3. VITE_ 변수를 공개 값으로만 사용했는가
Vite는 VITE_ 접두사가 붙은 환경변수를 import.meta.env를 통해 클라이언트 코드에 제공합니다. 공식 문서도 이 변수에 API 키 같은 민감정보를 넣지 말라고 명시합니다. Lovable·Bolt로 만든 Vite 앱에서 VITE_SUPABASE_SERVICE_ROLE_KEY, VITE_STRIPE_SECRET_KEY 같은 이름이 보인다면 이름을 바꾸는 것으로 끝내지 말고 서버 함수로 이동해야 합니다.
4. 비밀을 읽는 코드가 실제 서버 경계 안에 있는가
접두사를 제거해도 Client Component나 브라우저용 유틸리티가 값을 필요로 한다면 설계가 잘못된 것입니다. 브라우저는 필요한 작업을 서버 API에 요청하고, 서버가 비밀키로 외부 서비스와 통신한 뒤 최소한의 결과만 반환해야 합니다. 결제 금액·사용자 역할·대상 데이터 ID는 브라우저 요청을 그대로 신뢰하지 말고 서버에서 현재 사용자와 데이터베이스를 기준으로 다시 검증하세요.
5. Production·Preview·Development 범위를 분리했는가
Vercel은 Production, Preview, Development 환경별로 변수를 지정할 수 있습니다. 운영 데이터베이스와 결제 키를 모든 Preview 브랜치에 복사하면 테스트 링크 하나가 운영 자원에 접근하는 통로가 됩니다. Preview에는 테스트 프로젝트, 제한된 권한의 토큰과 샌드박스 결제를 연결하고 Production 자격 증명은 Production에만 적용하세요.
브랜치별 Preview 변수가 필요한 경우 특정 브랜치에만 값을 덮어쓸 수 있습니다. “Preview 전체”에 관리자 키 하나를 공유하는 대신 필요한 브랜치와 기간을 제한하고, 작업이 끝나면 접근을 제거합니다.
6. 중요한 값은 Sensitive 환경변수로 설정했는가
Vercel의 Sensitive 환경변수는 생성 뒤 값을 읽을 수 없는 형태로 보관됩니다. Production과 Preview 환경에서 사용할 수 있으며, 기존 일반 변수를 Sensitive로 바꾸려면 제거 후 다시 추가해야 합니다. 이는 대시보드에서의 불필요한 열람을 줄이지만, 애플리케이션 런타임의 과도한 권한이나 브라우저 번들 노출까지 막아주는 기능은 아닙니다.
7. 환경변수 변경 뒤 새 배포를 만들었는가
Vercel 공식 문서에 따르면 환경변수 변경은 이전 배포에 소급 적용되지 않고 새 배포부터 반영됩니다. 키를 교체한 뒤 대시보드만 저장하고 끝내면 현재 운영 배포는 계속 이전 값을 사용할 수 있습니다. 새 Production 배포를 만든 뒤 실제 API 호출이 새 키로 성공하고, 폐기한 키로는 실패하는지 확인하세요.
NEXT_PUBLIC_과 VITE_ 값은 빌드 시점에 번들로 고정됩니다. 하나의 빌드 산출물을 다른 환경으로 승격할 때도 당시 값이 남을 수 있으므로 배포별 빌드 기준을 문서화해야 합니다.
8. 응답·로그·오류 화면에 값을 출력하지 않는가
console.log(process.env), 오류 객체 전체 출력, 디버그용 JSON 응답은 서버 전용 변수를 외부로 옮길 수 있습니다. 키의 앞뒤 몇 글자도 여러 로그를 결합하면 식별에 쓰일 수 있으므로 로그에는 변수 이름, 성공 여부와 마스킹된 식별자만 남기세요. 사용자 오류 화면에는 내부 스택, 요청 헤더와 외부 서비스 응답 본문을 그대로 표시하지 않습니다.
9. 배포된 자바스크립트와 소스맵을 직접 검색했는가
설정 화면만 보지 말고 실제 Production 배포를 확인하세요. 브라우저 개발자 도구의 Network에서 .js 파일을 내려받아 키 접두사, 프로젝트 URL, 토큰 일부와 service_role 같은 문자열을 검색합니다. 공개 소스맵이 있다면 원본 소스와 주석에 비밀값·내부 URL·테스트 계정이 남지 않았는지도 확인하세요.
NEXT_PUBLIC_, VITE_, service_role, sk_live_, DATABASE_URL, 내부 관리자 도메인과 실제 키의 앞 6~8자. 키 전체를 검색 도구나 외부 서비스에 붙여넣지는 마세요.10. 노출된 키를 삭제이 아니라 교체했는가
비밀이 Git 기록, 빌드 번들, 로그 또는 공개 응답에 한 번이라도 포함됐다면 Vercel에서 변수만 지우는 것으로는 부족합니다. 발급 서비스에서 기존 키를 폐기하고 새 키를 만들고, 권한을 최소화한 뒤 Vercel 환경변수를 갱신하고 재배포하세요. 공개 배포·Preview·캐시·소스맵에서 이전 값이 더 이상 보이지 않는지도 다시 확인합니다.
출시 전 15분 실행 순서
- Vercel Settings의 환경변수 이름과 Production·Preview·Development 범위를 내보내지 않고 화면에서 대조합니다.
NEXT_PUBLIC_·VITE_목록에서 브라우저 공개가 의도된 값만 남깁니다.- 서버 비밀을 사용하는 파일이 Client Component나 브라우저 번들에 포함되지 않는지 확인합니다.
- Production 자바스크립트와 공개 소스맵에서 키 패턴을 검색합니다.
- 테스트 계정으로 권한 없는 API 요청을 보내 서버가 사용자 권한을 다시 검증하는지 확인합니다.
- 노출 이력이 있는 키는 폐기·재발급하고 새 배포 뒤 이전 키가 실패하는지 확인합니다.
공식 참고 자료
- Vercel Environment Variables — 환경별 변수 범위, 저장과 새 배포 적용 방식
- Vercel Sensitive Environment Variables — 읽을 수 없는 민감 변수와 적용 환경
- Vercel 환경별 변수 관리 — Production·Preview·Development 및 브랜치별 설정
- Next.js Environment Variables —
NEXT_PUBLIC_빌드 인라인과 서버 변수 - Next.js
next.config.js env— 번들에 포함되는 설정값 주의 - Vite Env Variables and Modes —
VITE_변수의 클라이언트 노출
함께 볼 가이드
- OpenAI API 키 노출 방지 가이드
- Supabase Auth 보안 체크리스트
- .env 파일이 브라우저에서 열리는 이유와 막는 법
- Supabase RLS 보안 체크리스트
- Supabase Storage 보안 체크리스트
- Lovable 앱 출시 전 체크리스트
자주 묻는 질문
Vercel 환경변수에 저장하면 비밀키가 자동으로 안전해지나요?
Vercel 환경변수는 저장 시 암호화되지만, 애플리케이션 코드가 값을 브라우저 번들에 넣거나 응답·로그에 출력하면 공개됩니다. 저장 위치뿐 아니라 변수가 사용되는 실행 경계를 함께 확인해야 합니다.
NEXT_PUBLIC_이나 VITE_ 변수에는 무엇을 넣어도 되나요?
브라우저에 공개되어도 되는 값만 넣어야 합니다. Next.js의 NEXT_PUBLIC_과 Vite의 VITE_ 변수는 빌드 결과에 포함될 수 있으므로 service role, 결제 시크릿, 데이터베이스 비밀번호와 관리자 토큰을 넣으면 안 됩니다.
Vercel에서 환경변수를 바꾸면 기존 배포에도 바로 적용되나요?
아닙니다. 변경된 환경변수는 새 배포부터 적용됩니다. 특히 브라우저에 인라인된 공개 변수는 빌드 시점 값으로 고정되므로 수정 후 새 배포와 실제 응답을 확인해야 합니다.
Preview 배포에도 Production 비밀키를 써도 되나요?
가능하면 분리하세요. Preview는 더 많은 사람이 접근하거나 여러 브랜치에서 실행될 수 있습니다. 별도 테스트 데이터베이스와 제한된 권한의 키를 사용하고, Production 전용 자원은 Production 환경에만 연결하는 편이 안전합니다.
공개 URL에서 노출 파일·브라우저 번들·보안 헤더를 먼저 확인하고, 로그인 기능은 테스트 계정으로 권한 경계를 별도 점검하세요.
무료로 위험 확인