Skip to content

原型链污染(Prototype Pollution)

攻击者通过可控对象合并(如 Object.assign、递归 merge、不安全反序列化),向 Object.prototype(或其它内置原型)写入属性,从而影响 全局所有对象 的行为,常与 Lodash 旧版合并、JSON.parse 后递归合并等场景相关。


攻击载荷思路(键名含 __proto__

恶意 JSON:

json
{
  "__proto__": {
    "isAdmin": true
  }
}

若自定义合并函数未过滤原型键,可能导致任意对象的 isAdmin 被误判。


不安全合并示意

js
function shallowMerge(target, src) {
  for (const k of Object.keys(src)) {
    target[k] = src[k];
  }
  return target;
}
shallowMerge({}, JSON.parse('{"__proto__":{"polluted":true}}'));
// 可能污染 Object.prototype(取决于 Node/引擎与是否可枚举等,实际利用需结合环境)

更常见的是 深度合并 未排除 __proto__constructor.prototype


安全做法

  1. 使用无原型对象作数据载体(减少污染面):
js
const data = Object.create(null);
data.name = 'ok';
  1. 合并前过滤键
js
const FORBIDDEN = new Set(['__proto__', 'constructor', 'prototype']);

function safeKey(k) {
  return !FORBIDDEN.has(k);
}
  1. 使用经过安全审计的库并升级(如 lodash 的 merge 在较新版本中已处理相关案例),或 只在服务端用 schema 严格解析

  2. 冻结内置原型(高阶、需谨慎):

js
// 仅作环境加固示例,可能影响部分库
Object.freeze(Object.prototype);

小结

前端若合并 不可信对象(URL 参数、第三方 JSON、开放 API 返回),必须 拒绝原型相关键 或使用 无原型对象;业务鉴权 不能 依赖「对象上多出来的 flag」而必须 服务端强校验