最有效防御是尽早冻结关键原型对象。必须在页面首个<script>顶部执行Object.freeze(Object.prototype)等六类原型冻结,并配合Object.create(null)、白名单校验、严格模式等业务层防护措施。

直接修改原型对象(比如 Object.prototype、Array.prototype)会让所有实例继承恶意或错误行为,造成全局污染。这不是“写错代码”的小问题,而是运行时环境被悄悄改写——所有对象都可能意外拥有被注入的属性,比如 admin: true 或篡改过的 toString。
尽早冻结关键原型对象
用 Object.freeze() 锁死原型,是最基础也最有效的硬隔离手段。它让原型进入不可变更状态:不能新增、删除、修改任何自有属性,也不能改变属性描述符。
- 必须在页面第一个
<script>的最顶部执行,早于所有第三方脚本(含 polyfill、埋点 SDK、分析工具) - 要冻结的原型包括:
Object.freeze(Object.prototype)Object.freeze(Array.prototype)Object.freeze(Function.prototype)Object.freeze(String.prototype)Object.freeze(Boolean.prototype)Object.freeze(Date.prototype) -
Math没有prototype,但可安全调用Object.freeze(Math)(非必需,无副作用)
业务层避免依赖普通对象做配置或映射
普通对象({})默认继承 Object.prototype,天然带污染风险。只要攻击者控制了键名,就可能写入 "__proto__" 或 "constructor"。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 配置对象、路由表、字段映射等场景,改用
Object.create(null)创建无原型对象 - 需要键值存储且要求绝对安全时,优先使用
Map:它不继承任何原型,键支持任意类型,不触发原型链查找 - 避免用
for...in遍历普通对象;改用Object.keys(obj)或Map.keys(),减少隐式原型访问
过滤用户输入,堵住污染入口
冻结原型是兜底防线,但污染往往发生在数据合并阶段。不能把不可信输入当路径或属性名来用。
立即学习“Java免费学习笔记(深入)”;
- 解析 JSON 或接收 URL 参数后,合并进目标对象前,必须过滤敏感键名:
"__proto__"、"constructor"、"prototype"及其大小写变体(如"__PROTO__") - 推荐白名单校验:只允许明确需要的字段名,其余一律丢弃
- 避免使用存在漏洞的深拷贝工具(如旧版
lodash.merge),升级到修复版本,或改用structuredClone()(现代环境支持)
监控与防御性编码习惯
冻结和过滤能拦住大部分攻击,但真实环境还需主动识别异常。
- 在开发或测试环境启用严格模式(
"use strict"),让原型污染操作立即抛出TypeError,便于快速发现 - 对关键方法(如
hasOwnProperty、toString)做运行时检查,例如:if (Object.prototype.hasOwnProperty !== {}.hasOwnProperty) console.warn("hasOwnProperty 被污染") - 第三方脚本尽量沙箱化:用
<iframe sandbox>或Web Worker隔离高风险模块

















