설명
Webpack DefinePlugin에서 process.env 전체를 직렬화해 정의하면, 해당 참조를 치환하는 과정에서 비밀 값까지 클라이언트 번들에 포함될 수 있습니다. 실제 포함 여부는 참조 코드와 최적화에 따라 달라지지만, 빌드 환경 전체를 공개 대상으로 삼으면 안 됩니다. 프론트엔드 번들은 누구나 내려받을 수 있으므로, API 키·토큰·비밀값이 그대로 노출될 수 있습니다. 공격자는 배포된 JS 파일(또는 source map)을 열람하거나, 코드 내에서 노출된 값들을 검색해 비밀정보를 수집할 수 있습니다.
잠재적 영향
- 자격 증명/API 키 노출: 번들에 포함된 키·토큰을 누구나 뷰-소스/DevTools로 확인 가능.
- 백엔드 무단 접근: 노출된 자격정보로 API 호출, 데이터 조회·변조 시도.
- 계정 남용 및 과금 피해: 제3자 서비스 키 악용으로 트래픽 유발, 비용 증가.
- 규정 위반 및 평판 하락: 개인정보/보안정책 위반으로 법적 제재 및 신뢰도 하락.
해결 방법
- DefinePlugin에 process.env 전체를 전달하지 말고, 공개가 허용된 소수의 키만 허용 목록으로 명시해 주입하세요.
- 서버 전용 Secret은 절대 클라이언트로 노출하지 마세요. 공개 허용 변수에 PUBLIC_ 같은 접두사를 부여해 구분하는 정책을 사용하세요.
- .env 파일을 용도별로 분리(.env.server, .env.client, .env.production 등)하고, CI/CD에서 클라이언트 빌드에 필요한 공개 변수만 export하세요.
- webpack DefinePlugin에서 개별 키를 정의하거나 EnvironmentPlugin(['NODE_ENV','PUBLIC_API_BASE'])처럼 지정된 목록만 허용하세요.
예시
변경 전
javascript
// webpack.config.js (취약)
const { DefinePlugin } = require("webpack");
// 전체 환경을 치환 값으로 정의 -> 참조 코드에 민감정보가 포함될 수 있음
const exposeAll = { "process.env": JSON.stringify(process.env) };
module.exports = {
mode: "production",
plugins: [new DefinePlugin(exposeAll)],
};
변경 후
javascript
// webpack.config.js (안전)
const { DefinePlugin, EnvironmentPlugin } = require("webpack");
require("dotenv").config();
// 공개가 허용된 키만 화이트리스트로 노출 (예: PUBLIC_ 접두사)
const PUBLIC_VARS = {
"process.env.NODE_ENV": JSON.stringify(process.env.NODE_ENV),
"process.env.APP_VERSION": JSON.stringify(require("./package.json").version),
"process.env.PUBLIC_API_BASE": JSON.stringify(process.env.PUBLIC_API_BASE),
};
module.exports = {
mode: "production",
plugins: [
new DefinePlugin(PUBLIC_VARS),
// 또는 필요한 키만 명시적으로 허용
// new EnvironmentPlugin(['NODE_ENV', 'PUBLIC_API_BASE'])
],
};
설명:
- 변경 전: process.env 전체를 직렬화하여 번들에 포함하면, 원래 서버 전용이어야 할 비밀값(예: API 키, 액세스 토큰, DB 연결 정보)이 공개 아티팩트에 남습니다. 사용자는 배포된 JS 파일이나 source map을 열람하여 해당 값을 쉽게 획득할 수 있습니다.
- 변경 후: DefinePlugin으로 공개가 허용된 변수만 개별적으로 정의해 노출 범위를 최소화합니다. PUBLIC_ 등 접두사 정책을 통해 클라이언트로 내보낼 변수만 선택하고, 나머지 Secret은 서버에서만 사용하도록 분리합니다. 접두사 자체가 비밀 값을 보호하지는 않으므로 선택한 값이 실제로 공개 가능한지 검토하고, 다른 번들·source map 경로의 노출도 확인하세요.