防范原型链污染需在脚本执行初始即冻结原生原型链,如object.freeze(object.prototype)等,并改用object.create(null)替代{},禁用不安全合并函数,升级或自研安全深拷贝,辅以运行时监控与检测。

防范黑客利用原型链污染篡改 Object.prototype,核心不是等崩溃发生再补救,而是在脚本执行最开始就切断所有写入路径。这类攻击一旦成功,所有基于 class 创建的实例(包括 Array、String、自定义类等)都会继承恶意属性或覆盖关键方法(如 toString、hasOwnProperty),轻则逻辑错乱,重则整个对象体系行为失常甚至无法实例化。
启动时冻结原生原型链
这是最直接、最底层的硬性防护,必须在任何第三方脚本(包括 CDN 脚本、埋点 SDK、广告代码)加载前完成:
- 在 HTML 的第一个
<script></script>标签顶部立即执行:Object.freeze(Object.prototype);Object.freeze(Array.prototype);Object.freeze(Function.prototype);Object.freeze(String.prototype);Object.freeze(Boolean.prototype);Object.freeze(Date.prototype); - 严格模式下,尝试向已冻结原型添加属性会立即抛出
TypeError;非严格模式下虽静默失败,但同样能阻断污染 - 注意兼容性:极少数老旧环境(如 IE10 及更早)不支持
Object.freeze,若需兼容,应结合运行时检测与降级策略
配置与数据容器改用无原型对象
避免使用 {} 作为缓存、参数映射、配置接收器等通用容器——它天然继承 Object.prototype,是污染的“放大器”:
- 统一替换为
Object.create(null),例如:const config = Object.create(null);const cache = Object.create(null); - 这种对象没有
__proto__、不继承任何方法(如toString、hasOwnProperty),从根本上杜绝原型链查找被污染影响 - 若需保留部分方法,可显式挂载(如
config.hasOwnProperty = Object.prototype.hasOwnProperty.bind(config)),但通常纯键值场景无需此操作
严控对象合并与深拷贝入口
绝大多数污染发生在处理用户输入(JSON、URL 参数、表单数据)时的不安全合并操作:
- 禁用高危函数:避免使用
lodash.merge、deepmerge(旧版)、手写递归赋值等未过滤敏感键的逻辑 - 升级依赖:确保
lodash ≥ 4.17.21,并启用其内置防护(如_.mergeWith配合自定义customizer过滤__proto__、constructor、prototype) - 优先选用安全替代:
— 浅拷贝用Object.assign({}, input)
— 深拷贝用原生structuredClone(input)(现代浏览器及 Node.js ≥17.0)
— 若需兼容旧环境,自研深拷贝函数必须递归校验每个键名,对/\b(__proto__|constructor|prototype)\b/i全路径匹配并跳过
运行时监控与主动验证
防御不能只靠静态规则,需加入动态感知能力:
- 上线前/预发阶段注入检测 payload:
JSON.parse('{"__proto__": {"polluted": true}}');
随后执行({ }).polluted === true,若为true则说明已失守 - 对关键入口(如
JSON.parse、req.body、location.search解析结果)增加字段扫描逻辑,发现敏感键立即记录上下文并告警 - 在开发环境用
Proxy包裹Object.prototype(仅限调试),拦截所有set操作并打印调用栈,快速定位污染源头











