runtimeConfig에 넣은 API 키가 브라우저 소스에 보인 이유
문제 발생
외부 API 키를 runtimeConfig에 넣고 컴포넌트에서 꺼내 썼는데, 배포 후 브라우저 소스에서 그 키가 그대로 보였습니다.
// nuxt.config.ts
runtimeConfig: {
apiSecret: process.env.API_SECRET,
}<script setup>
const config = useRuntimeConfig();
const data = await $fetch("https://api.example.com", {
headers: { Authorization: config.apiSecret }, // ❌
});
</script>원인 분석
runtimeConfig는 두 층입니다.
- 최상위 키 — 서버에서만 접근 가능한 값입니다. API 시크릿처럼 민감한 데이터가 여기 들어갑니다.
public객체 — 클라이언트에 노출되며 브라우저에서도 읽을 수 있습니다. 공개 API base URL처럼 민감하지 않은 값만 둡니다.
문제는 "서버 전용"이 접근 위치의 문제라는 점입니다. <script setup>은 서버에서도 클라이언트에서도 실행됩니다. 서버에서 읽은 값을 렌더 결과나 상태에 실으면 그대로 브라우저까지 갑니다.
Nuxt 공식 문서가 이걸 경고로 적습니다 — 런타임 설정 키를 렌더링하거나 useState에 넘겨서 클라이언트에 노출하지 않도록 주의하십시오.
해결 방안
- 비밀값을 쓰는 요청은 서버 라우트로 옮깁니다. 브라우저는 우리 서버만 부르고, 외부 API 호출과 키 사용은 서버에서 일어납니다.
// server/api/quotes.get.ts
export default defineEventHandler(async () => {
const config = useRuntimeConfig();
return await $fetch("https://api.example.com/quotes", {
headers: { Authorization: config.apiSecret },
});
});<script setup>
const { data } = await useFetch("/api/quotes"); // 키가 브라우저로 가지 않음
</script>- 공개해도 되는 값만
public에 둡니다.
runtimeConfig: {
apiSecret: "", // 서버 전용
public: {
apiBase: "https://meokko.com/api", // 클라이언트 노출 OK
},
}- 환경변수 이름 규칙을 지킵니다. 접두사가 곧 층을 정합니다.
| 설정 키 | 환경변수 |
|---|---|
apiSecret | NUXT_API_SECRET |
public.apiBase | NUXT_PUBLIC_API_BASE |
값은 destr로 자동 형변환됩니다 — 문자열로 유지해야 하면 따옴표를 포함해 적습니다.
-
nuxt.config에 기본값을 빈 문자열로 둡니다. 실제 값은 환경변수로 주입합니다. 코드에 진짜 키를 적어두면 저장소에 남습니다. -
호출 위치가 정해져 있습니다.
useRuntimeConfig()는 컴포넌트 setup, 플러그인, 미들웨어, 서버 라우트 핸들러 안에서만 부를 수 있습니다. 모듈 최상단에서 부르면 동작하지 않습니다. -
useState에 담지 않습니다.useState값은 payload로 직렬화되어 브라우저로 전달됩니다. 경고가 콕 집어 언급하는 경로입니다. -
이미 유출됐다면 키를 폐기합니다. 코드를 고치는 것으로 이미 배포된 번들과 브라우저 캐시에서 회수되지 않습니다.
댓글0
댓글을 남기려면 로그인이 필요해요. 로그인
아직 댓글이 없어요. 첫 의견을 편하게 남겨 보세요.