JavaScript模块本身不直接引发XSS或全局污染,但动态import()拼接用户输入、导出可变对象致原型污染、HTML模板直接插入模块数据、export *导致tree-shaking失效等用法会放大安全风险。

JavaScript模块系统本身不直接导致XSS或全局污染,但模块加载方式、导出/导入逻辑以及与DOM交互的时机,可能放大安全风险。关键不在“是否用模块”,而在“如何用模块”。
动态import()与XSS风险
使用import()加载远程模块(如import('https://' + userInput + '/widget.js'))极易触发CSP绕过和远程代码执行。浏览器会将响应体当作JavaScript执行,若服务端未严格校验来源或返回内容被注入恶意脚本,就等同于eval()不受控代码。
- 禁止拼接用户输入构造模块路径;必须白名单校验或使用绝对静态路径
- 配合CSP策略script-src 'self',禁用unsafe-inline和unsafe-eval
- 远程模块应通过可信CDN提供,且启用Subresource Integrity(SRI)校验哈希
默认导出与原型污染隐患
当模块导出一个可变对象(如module.exports = { config: {} }),而外部代码执行obj.__proto__.admin = true或Object.prototype.polluted = 1时,若后续模块依赖该对象的原型链行为,就可能被污染影响。ESM中虽无法直接改写export default绑定,但若导出的是引用类型(如对象、数组),其内部属性仍可被修改。
- 优先导出不可变结构:用Object.freeze()封装配置对象,或使用const声明+字面量初始化
- 避免在模块顶层暴露可变全局状态;改用工厂函数按需生成独立实例
- 在入口模块中主动防御:Object.setPrototypeOf({}, null)创建无原型对象,或使用Map替代普通对象存储配置
HTML模板字符串中的模块变量注入
常见错误是把模块导出的数据直接插入DOM,例如document.body.innerHTML = `
立即学习“Java免费学习笔记(深入)”;
- 模块只负责数据流转,不承担渲染职责;渲染逻辑应由专用视图层处理,并自动转义
- 若必须拼接HTML,用textContent代替innerHTML,或使用DOMPurify.sanitize()过滤
- 对模块间传递的数据做最小化信任:接收方应验证字段类型、长度、正则格式,而非假设“模块内数据天然可信”
Tree-shaking失效带来的隐蔽依赖
当构建工具(如Webpack、Rollup)因模块导出方式不当(如export * from './legacy.js')无法正确识别无用代码时,被标记为“未使用”但实际含副作用的模块仍会被打包。这些模块可能包含旧版DOM操作、document.write()或eval()调用,在运行时意外激活,成为XSS入口点。
- 避免使用export *,显式列出所需导出项,便于静态分析
- 在package.json中标注"sideEffects": false,或明确列出有副作用的文件
- 定期检查打包产物,用source-map-explorer确认敏感API是否残留


















