原型链污染会直接破坏javascript运行时环境,使攻击者在所有对象上悄无声息植入恶意行为;object.freeze通过冻结object.prototype等关键原型阻断污染写入,但必须在第三方脚本执行前调用,并配合object.create(null)、输入过滤、安全api等措施才真正可靠。

原型链污染会直接破坏 JavaScript 的运行时环境,让攻击者能在所有对象上“悄无声息”植入恶意行为,比如伪造权限、篡改数据、劫持方法调用,甚至触发远程代码执行;Object.freeze 是一道底层防线,它把 Object.prototype 等关键原型锁死,让污染写入操作失效——但必须早于任何第三方脚本执行,且需配合其他措施才真正可靠。
污染怎么引发真实安全风险
JavaScript 查找属性时会一路沿 __proto__ 向上,直到 Object.prototype。一旦这里被注入属性,所有对象(包括 {}、[]、new Date())都会继承它:
- 覆盖 toString 或 valueOf:可能绕过 JSON 序列化校验、干扰模板渲染、隐藏恶意数据
- 添加 admin、isSuperUser 等字段:使权限判断逻辑误判,例如 if (user.admin) 意外为 true
- 污染 hasOwnProperty:导致 Object.keys、for...in 等遍历行为异常,引发配置解析失败或跳过安全检查
- 结合框架特性触发 RCE:如 Express 中污染 constructor.prototype 可能影响中间件加载,Vue CLI 旧版曾因 merge 操作被利用执行任意代码
Object.freeze 的实际防御效果
它不是加个“锁”,而是让原型对象进入不可变更状态:无法新增、删除、修改任何自有属性,也无法改变属性描述符。在严格模式下尝试污染会立即报错,非严格模式下也静默失败,从而阻断攻击链。
- 必须冻结多个原型:Object.freeze(Object.prototype)、Object.freeze(Array.prototype)、Object.freeze(Function.prototype)、Object.freeze(String.prototype)、Object.freeze(Boolean.prototype)、Object.freeze(Date.prototype)
- 要放在最前面执行:在 HTML 中第一个 <script> 的顶部,确保早于所有第三方库(包括 polyfill 和分析脚本)</script>
- Math 不是构造函数,没有 prototype,但 Math 对象本身也可 freeze(非必需,但无害)
仅靠 freeze 远不够,还得做这几件事
冻结原型是硬隔离,但业务层仍需主动设防:
- 配置对象别用 {},改用 Object.create(null):它没有原型链,天然免疫,适合存配置、映射表等场景
- 解析外部数据后别直接 assign 或 merge:先过滤 __proto__、constructor、prototype 及大小写变体(如 __PROTO__),推荐用白名单校验字段名
- 替换不安全的工具:lodash.merge ≤4.17.11 有漏洞,升级到新版并启用 customizer;现代环境优先用 structuredClone 做深拷贝
- 服务端可加运行参数:Node.js 启动时加 --disable-proto=throw,强制拦截对 __proto__ 的赋值
如何验证防护是否生效
上线前和日常巡检可用简单测试确认:
- 注入测试 payload:JSON.parse('{"__proto__": {"polluted": true}}'),然后检查 ({}).polluted 是否为 undefined
- 日志监控入口点:在解析请求体、读取 config.json 等位置记录原始输入,发现含 __proto__ 字段立即告警
- 静态扫描:用 ESLint 插件(如 eslint-plugin-security)标记 _.merge、JSON.parse 后直接合并等高危模式
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











