原型污染需在数据入口处设防,禁止用户输入触碰Object.prototype敏感键,强制清洗所有外部输入,禁用高危合并函数,优先使用Object.create(null)和structuredClone(),并辅以运行时监控。

原型污染不是配置开关能关掉的问题,而是得在数据进来的第一刻就设防。核心思路很明确:不让任何用户输入有机会碰触 Object.prototype,尤其避开 __proto__、constructor、prototype 这些键。
所有外部输入必须清洗敏感路径
JSON 请求体、URL 查询参数、表单字段——只要来自用户,就必须在进入业务逻辑前做递归扫描。
- 不能只检查顶层 key,像
{"a": {"__proto__": {"x": 1}}}或{"x.__proto__.y": "z"}都要匹配到 - 推荐正则:
/\b(__proto__|constructor|prototype)\b/i,对每个 key 和完整路径字符串都跑一遍 -
JSON.parse()后第一行代码就该是清洗,别等到合并或赋值时才处理
对象操作避开高危函数
很多深拷贝和合并工具默认不校验原型键,一用就中招。
- 禁用
_.merge、_.set、_.defaultsDeep处理用户数据;若必须用,确保 lodash ≥ 4.17.21 - 浅拷贝优先用
Object.assign({}, input),它不递归,天然跳过污染路径 - 需要深拷贝时,现代环境直接用
structuredClone();Node.js 可加启动参数--disable-proto=throw - 手动递归赋值时,遇到敏感键名直接跳过,不往下递归
用无原型对象替代普通空对象
当你只需要一个纯键值容器(比如缓存、路由参数映射、插件注册表),就别再用 {}。
- 改用
Object.create(null)创建对象,它没有__proto__,也不继承任何方法 - 代价是不能直接调用
obj.toString()或obj.hasOwnProperty(),需显式借用:Object.prototype.hasOwnProperty.call(obj, key) - 适合所有你本就不希望它有“行为”的场景,从根源上切断污染可能
运行时加一层兜底防护
静态防御可能被绕过,上线后仍需动态监控与快速响应。
- 预发环境定期注入测试 payload,例如
{"__proto__": {"polluted": true}},验证({ }).polluted === true是否成立 - 在日志中对
JSON.parse、req.body、fs.readFileSync等入口点添加字段扫描,命中敏感键立即告警 - 高安全要求场景可启动时执行
Object.freeze(Object.prototype),但注意兼容性,部分老库会因此报错


















