Webpack构建时应使用compilation.hooks.processAssets钩子(stage设为PROCESS_ASSETS_STAGE_DERIVED或更晚),通过getRawAsset读取原始Buffer、正则匹配敏感字符串、updateAsset显式更新,确保覆盖拼接字符串、模板字面量及第三方库硬编码内容。

构建时用 Webpack 插件扫描并替换敏感字符串
Webpack 构建阶段介入是最直接的方式,核心是利用 compilation.hooks.processAssets(Webpack 5+)在代码生成后、输出前做文本级扫描与替换。不推荐用 loader 处理,因为 loader 面向模块源码,无法覆盖拼接字符串、模板字面量或第三方库内硬编码的敏感字段。
常见错误现象:processAssets 钩子未指定 stage 导致执行时机过早,assets 还未被序列化为字符串;或直接修改 source().toString() 后没调用 updateAsset,导致变更不生效。
- 必须设置
stage: webpack.Compilation.PROCESS_ASSETS_STAGE_DERIVED或更晚阶段 - 对每个 asset 调用
getRawAsset获取原始 Buffer,避免 UTF-8 解码错误(尤其含中文注释时) - 替换后需用
compilation.updateAsset(filename, newSource)显式更新,否则无效 - 正则需加
g标志且注意转义,例如匹配password:后内容:/password\s*:\s*["']([^"']*)["']/gi
用 Rollup 插件在 generate 阶段过滤敏感字面量
Rollup 的 generateBundle 钩子适合处理已打包但未写入磁盘的最终代码块,比 transform 更可靠——后者可能因 tree-shaking 或 code-splitting 导致敏感字符串分散在多个 chunk 中漏检。
典型使用场景:微前端子应用独立构建,需确保所有 .js 输出中不含 apiKey、authToken 等硬编码值,但又不想改业务代码逻辑。
- 遍历
bundle对象的每个chunk,用chunk.code做字符串匹配 - 避免用
replace()全局无差别替换,应保留原始字符串结构(如只清空值,不删键名):/(apiKey\s*:\s*)["'][^"']*["']/g→$1"" - 若项目含 source map,需同步更新
chunk.map,否则调试时定位错乱;可借助magic-string库安全替换并生成新 map - 敏感词列表建议从环境变量读取(如
process.env.SENSITIVE_KEYS),避免插件代码里硬编码
Vite 插件如何在 build.closeBundle 里安全擦除
Vite 的 build.closeBundle 是构建收尾钩子,此时所有产物已生成但尚未压缩,是做最终文本清洗的最后机会。相比 transform,它能覆盖 esbuild 压缩后的代码,防止 minify 把敏感字符串混淆成不可识别形态后逃逸。
容易踩的坑:Vite 默认启用 esbuild.minify,若在 transform 阶段处理,可能因压缩提前合并字符串(如 "api"+"Key" → "apiKey")导致正则失效;而 closeBundle 拿到的是压缩后、未 gzip 的原始文件内容。
- 用
fs.readFileSync(outputPath, 'utf-8')读取每个.js文件(注意outputPath来自config.build.outDir) - 替换后必须调用
fs.writeFileSync覆盖原文件,Vite 不会自动回写 - 慎用
fs.rmSync删除重写,Windows 下可能报 EBUSY;优先用writeFileSync原地覆盖 - 若开启
build.sourcemap,需同时处理同名.js.map文件,但 map 本身不含敏感内容,通常只需确保其sourcesContent字段未泄露(可设为null)
为什么不能只依赖 ESLint 或 TypeScript 类型检查
ESLint 规则(如 no-console)和 TS 类型系统只能约束开发时的显式写法,对运行时拼接、JSON 配置注入、eval 动态执行等场景完全无效。曾有项目在 fetch 参数里用 process.env.PRIVATE_TOKEN,TS 编译通过,ESLint 无告警,但构建产物里明文暴露了 token。
真正起作用的是构建时的“字节流清洗”——不管字符串怎么来,只要最终 JS 文件里存在匹配模式,就强制替换。这也是为什么所有方案都绕不开正则 + 文件 I/O,而不是语法树分析。
最易被忽略的一点:第三方 npm 包里的敏感字符串(比如某个埋点 SDK 硬编码了测试环境 auth key)。构建插件默认不处理 node_modules,必须显式配置白名单路径或用 include 选项扩大扫描范围,否则等于没防住。

















