__proto__是原型污染最直接入口,因其作为内部原型链接被误作普通键写入时会污染object.prototype;须用正则/\b(__proto__|constructor|prototype)\b/i递归扫描所有键及嵌套路径,json.parse后立即清洗,并优先采用object.create(null)、object.assign或structuredclone等安全替代方案。

“__proto__”是原型污染攻击最直接、最常见的入口点。它不是普通属性,而是JavaScript中指向对象原型的内部链接——一旦被当作键名写入,就可能把恶意属性注入到Object.prototype,让所有对象“自动继承”。
为什么 __proto__ 特别危险
它在对象赋值或合并时不会被当作普通字段处理,而是触发原型链修改。比如:
• JSON.parse('{"__proto__": {"isAdmin": true}}') 后直接 Object.assign({}, parsed),会导致 {} 甚至 new Date() 都拥有 isAdmin
• 攻击者常构造嵌套路径如 "a.__proto__.b" 或 "x.constructor.prototype.y" 绕过只检查顶层键的防护
必须拦截的敏感路径模式
不能只匹配字面量 "__proto__",要覆盖所有变体和组合:
- 正则推荐:
/\b(__proto__|constructor|prototype)\b/i,对每个 key 和完整路径字符串都执行匹配 - 需递归扫描:包括
{"a": {"__proto__": {...}}}、{"x.y.__proto__.z": "val"}、{"__PROTO__": 1}(大小写不敏感) - JSON.parse 后第一行代码就该做清洗,而不是等到 merge 或 set 时才校验
替代方案:从源头切断依赖
不用 __proto__,就不用防它。关键做法是避开有原型的对象:
- 用
Object.create(null)替代{}创建纯字典对象,它没有__proto__,也不继承任何方法 - 浅拷贝优先选
Object.assign({}, input)—— 它不递归,天然跳过深层污染路径 - 现代环境用
structuredClone()做深拷贝,它不走原型链,也支持循环引用
运行时加固作为兜底
即使前端做了过滤,服务端仍需多一层保险:
- Node.js 启动时加
--disable-proto=throw,让任何访问__proto__的操作直接报错 - 高安全场景可执行
Object.freeze(Object.prototype),但需提前验证兼容性 - 日志中对
req.body、JSON.parse结果等入口点加字段扫描,命中敏感键立即告警











