- 위험도
- 치명적(Critical)
- CWE
- CWE-798 · 하드코딩된 자격증명
- OWASP
- A05:2021
- 룰
- vg-supabase-service-role-client · vg-public-env-secret · vg-llm-api-key-hardcoded
이게 무슨 말이냐 (쉽게)
웹앱은 브라우저에서 도는 코드(프론트)와 서버에서만 도는 코드(백)가 있어요. 비밀 키는 서버에만 있어야 합니다. 그런데 다음 셋 중 하나면 키가 사용자에게 새요.
- NEXT_PUBLIC_ / VITE_ / EXPO_PUBLIC_ 접두어 — 이 접두어가 붙은 환경변수는 설계상 브라우저로 그대로 복사됩니다. 여기에 비밀값(비밀번호·시크릿·service_role)을 넣으면 100% 노출이에요.
- service_role 키를 프론트에서 사용 — service_role은 RLS도 무시하는 마스터 키입니다. 프론트에 두면 그 자체로 게임 오버.
- 키를 코드에 직접 문자열로 (apiKey: "sk-proj-...") — 깃허브에 올리는 순간 봇이 몇 분 안에 긁어갑니다.
실제로 어떻게 터지나 (시나리오)
당신이 OpenAI로 챗봇을 붙였어요. 빠르게 만들려고 NEXT_PUBLIC_OPENAI_API_KEY에 키를 넣었죠. 사이트를 열면 그 키가 자바스크립트 번들 안에 평문으로 들어갑니다. 누군가 브라우저 소스 검색으로 sk- 만 쳐도 키가 나와요. 그 키로 당신 계정에 마음껏 API를 호출합니다.
최악의 경우
- OpenAI·클라우드 과금 폭탄 — 남이 당신 키로 수천 달러어치 호출. 아침에 일어나면 청구서가 와 있어요.
- service_role 노출이면 — RLS를 아무리 잘 걸어도 무력화. 전체 DB 읽기·쓰기·삭제가 다 뚫립니다.
- 키 회수·교체 동안 서비스 중단, 신뢰 추락.
나한테 해당되나? (체크)
- 환경변수에 NEXT_PUBLIC_·VITE_·EXPO_PUBLIC_을 붙였는데 이름에 SECRET·PASSWORD·API_KEY·SERVICE_ROLE·TOKEN이 있다.
- 프론트 컴포넌트("use client", .tsx)에서 service_role을 쓴다.
- 코드 어딘가에 sk-... , sk-ant-... , AIza... 같은 키를 직접 문자열로 적었다.
→ 하나라도 체크되면 즉시 아래대로 고치고, 키를 새로 발급(회수) 하세요. 이미 노출된 키는 고친다고 안전해지지 않아요.
어떻게 고치나 (복붙)
① 접두어를 떼고 서버 전용으로
- NEXT_PUBLIC_OPENAI_API_KEY=sk-proj-xxxx # 브라우저로 샘
+ OPENAI_API_KEY=sk-proj-xxxx # 서버에서만 읽힘② 호출은 서버에서 (Next.js Route Handler 예시)
// app/api/chat/route.ts ← 서버에서만 실행됨
import OpenAI from "openai";
const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY }); // 접두어 없음
export async function POST(req: Request) {
// 여기서 호출하고 결과만 프론트로 돌려줌
}③ service_role은 절대 프론트에 두지 않기 — 관리자 작업은 서버 라우트에서만.
// 서버 전용 파일에서만
const admin = createClient(process.env.SUPABASE_URL!, process.env.SUPABASE_SERVICE_ROLE_KEY!);④ 이미 노출된 키는 회수·재발급 — OpenAI·Supabase·Stripe 대시보드에서 기존 키 폐기 → 새 키 발급. 그리고 .env는 .gitignore에 넣어 깃에 안 올라가게.
고친 뒤 확인
- 01
번들에서 검색해 보기
빌드 후 브라우저에서 사이트 열기 → 소스 검색 sk- , service_role → 안 나와야 정상.
- 02
깃 기록 훑기
git grep -nE "sk-(ant-)?[A-Za-z0-9_-]{20,}" → 결과가 없어야 합니다.
- 03
도난 여부 확인
노출됐던 키는 대시보드에서 마지막 사용 시각을 확인. 낯선 IP·시간이면 이미 도난 가능 → 즉시 폐기.
규제 연결
자격증명 노출은 ISMS-P 2.7(암호화·비밀관리)·2.5(인증·권한), PIPA 제29조 안전조치의무에 직접 걸립니다. 리포트는 키를 실제로 회수했는지까지 한국어로 확인해 드립니다. 조항 매핑은 신뢰 센터의 참고 대조표에 있고, 리포트에 자동으로 붙지는 않습니다.
출처/더 읽기: OWASP A05:2021(Security Misconfiguration), CWE-798, Next.js 환경변수 공식 문서, Supabase 키 종류 문서. 이 카드는 우리가 직접 작성했습니다.
← 문서 목록으로