关键在于阻断向Object.prototype写入属性的路径,需三方面协同:运行时冻结原生原型(如Object.freeze(Object.prototype)等)、数据处理改用Object.create(null)替代{}、过滤__proto__等敏感键并坚持白名单机制,同时升级lodash至4.17.21+、启用structuredClone或--disable-proto=throw。

避免原型污染漏洞,关键在于阻断攻击者向 Object.prototype 写入属性的路径。这不是单点修复,而是需要从运行时防护、数据处理方式和依赖治理三方面协同加固。
冻结原生原型对象
在应用启动最早期(如 HTML 中第一个 <script></script> 顶部)执行以下操作,可强制锁定原型不可修改:
Object.freeze(Object.prototype)Object.freeze(Array.prototype)Object.freeze(Function.prototype)Object.freeze(String.prototype)Object.freeze(Boolean.prototype)Object.freeze(Date.prototype)
严格模式下尝试污染会立即抛出 TypeError;非严格模式下赋值静默失败,同样生效。注意:需确保执行时机早于任何第三方脚本,否则可能被绕过。
用无原型对象替代普通字面量
凡涉及用户输入、配置合并、路由参数、请求体解析等场景,避免使用 {},改用:
-
Object.create(null)创建空对象,它没有__proto__,属性查找失败即止,不向上遍历原型链 - 该对象不继承
toString、hasOwnProperty等方法,必要时用Object.prototype.hasOwnProperty.call(obj, key)替代 - 适用于插件配置、模板选项、JSON 解析后暂存结构等易受控数据容器
过滤敏感键名并坚持白名单机制
只要存在类似 target[key] = source[key] 的动态赋值逻辑,且 key 来自外部(URL 参数、表单、JSON 解析结果),就必须拦截:
- 明确禁止键名:
"__proto__"、"constructor"、"prototype",及其大小写变体(如"__PROTO__"、"Constructor") - 对深合并或递归赋值函数,在每一层递归入口检查当前 key,而非仅校验顶层
- 优先采用字段白名单:只允许已知安全字段(如
["name", "email", "avatar"])进入目标对象
升级依赖并选用安全 API
老旧工具链是污染高发区,必须主动治理:
- 升级
lodash至4.17.21+,其merge已默认跳过__proto__;避免使用已知有缺陷的深拷贝库(如旧版deepmerge) - 现代环境优先使用原生
structuredClone()进行深拷贝,它不遍历原型链、不触发 getter,更安全可靠 - Node.js 服务可启用
--disable-proto=throw启动参数,强制拦截所有__proto__访问











