核心是切断向object.prototype写入属性的路径,需运行时防护(如object.freeze原生原型)、数据处理规范(用object.create(null)替代{})、环境加固(过滤__proto__等敏感键、升级lodash/使用structuredclone)。

防止恶意脚本通过原型链进行污染攻击,核心是切断“向 Object.prototype 写入属性”这一关键路径。这不是靠某一个技巧就能一劳永逸,而是需要运行时防护、数据处理规范和环境加固三者配合。
冻结原生原型对象
这是最直接有效的硬性防御手段。调用 Object.freeze() 锁定原生构造函数的 prototype,让引擎拒绝任何新增、修改或删除操作:
-
必须在所有第三方代码执行前完成,通常放在 HTML 中第一个
<script></script>的顶部 - 需冻结多个关键原型:
Object.prototype、Array.prototype、Function.prototype、String.prototype、Boolean.prototype、Date.prototype - 严格模式下尝试污染会立即抛出
TypeError;非严格模式下虽不报错,但赋值静默失败,同样阻断攻击
避免使用普通对象做配置或数据容器
很多污染发生在把用户输入合并进配置对象时。改用无原型对象可天然免疫:
- 用
Object.create(null)替代{}创建空对象,它没有__proto__,查找不到属性就直接返回undefined,不会向上遍历 - 尤其适用于路由参数、请求体解析结果、模板选项、插件配置等可能被外部控制的场景
- 注意:这类对象不继承
toString、hasOwnProperty等方法,必要时需手动挂载或用Object.prototype.hasOwnProperty.call(obj, key)
过滤敏感键名,不信任任何输入
只要存在类似 target[key] = source[key] 的赋值逻辑,且 key 来自不可信来源(如 JSON 解析、URL 参数、表单提交),就必须拦截危险键:
- 明确禁止以下键名:
"__proto__"、"constructor"、"prototype",大小写变体也需考虑(如"__PROTO__") - 对深合并/递归赋值函数,应在每一层递归前检查当前 key 是否敏感,而不是只校验顶层
- 优先采用白名单机制:只允许已知安全字段(如
["name", "email", "age"])进入目标对象
升级依赖并选用安全 API
很多污染漏洞源于老旧工具链的缺陷实现:
- 升级
lodash至 4.17.21+,merge已默认跳过__proto__;避免使用已知有风险的深拷贝库(如旧版deepmerge) - Node.js 17+ 推荐使用原生
structuredClone()处理复杂对象拷贝,它不遍历原型链,也不执行 getter,更安全 - 后端服务若暴露管理接口,应确保其不与业务 API 共享同一上下文,防止污染后果横向扩散
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











