原型链污染(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。
安全做法
- 使用无原型对象作数据载体(减少污染面):
js
const data = Object.create(null);
data.name = 'ok';- 合并前过滤键:
js
const FORBIDDEN = new Set(['__proto__', 'constructor', 'prototype']);
function safeKey(k) {
return !FORBIDDEN.has(k);
}使用经过安全审计的库并升级(如 lodash 的
merge在较新版本中已处理相关案例),或 只在服务端用 schema 严格解析。冻结内置原型(高阶、需谨慎):
js
// 仅作环境加固示例,可能影响部分库
Object.freeze(Object.prototype);小结
前端若合并 不可信对象(URL 参数、第三方 JSON、开放 API 返回),必须 拒绝原型相关键 或使用 无原型对象;业务鉴权 不能 依赖「对象上多出来的 flag」而必须 服务端强校验。
