防范原型属性污染需切断用户数据向object.prototype写入路径,首选object.create(null)创建无原型对象,配合输入清洗、禁用高危函数及运行时加固。

避免原型属性污染,核心是切断用户可控数据向 Object.prototype 写入的路径。不是靠“少用原型”,而是主动控制对象的原型链起点——尤其在仅需键值容器的场景下,彻底不用继承自 Object.prototype 的对象。
优先使用 Object.create(null) 替代 {}
这是最直接、最彻底的防范方式。它创建的对象没有原型链,自然无法被污染:
- 适用场景明确:配置缓存、路由参数映射、插件注册表、临时数据聚合等纯字典用途
-
无 toString / hasOwnProperty 等方法,需显式调用:
Object.prototype.hasOwnProperty.call(obj, key) -
不兼容依赖原型的方法(如
obj instanceof Object为false),但这类判断本就不该用于数据容器
输入层强制清洗敏感键名
所有外部数据进入业务逻辑前必须过滤,不能依赖“后面再处理”:
- 对 JSON 解析后的对象递归扫描每个键名和嵌套路径,匹配正则
/\b(__proto__|constructor|prototype)\b/i - 特别注意深层污染形式,如
{"a": {"__proto__": {"x": 1}}}或{"x.__proto__.y": "z"} - 清洗动作应放在
JSON.parse()后第一行,而非合并或赋值环节
慎选对象操作方式,避开高危函数
很多合并/深拷贝工具默认不校验原型键,极易成为攻击入口:
- 禁用
_.merge、_.set、_.defaultsDeep处理不可信输入;若必须用,确保 lodash ≥ 4.17.21 - 浅拷贝优先用
Object.assign({}, input),它不递归,天然跳过污染路径 - 需要深拷贝时,现代环境首选
structuredClone();Node.js 可启用--disable-proto=throw
运行时加固作为兜底手段
静态防御可能被绕过,高安全要求场景建议加一层防护:
- 服务启动时执行
Object.freeze(Object.prototype),阻止新增/修改属性(注意:不可逆,需确认无合法依赖) - 预发环境注入测试 payload(如
{"__proto__": {"polluted": true}}),验证是否生效 - 在日志中对关键入口(如
req.body、fs.readFileSync)添加敏感键扫描与告警











