JavaScript原型链污染
字数 1051 2025-08-10 16:34:34
JavaScript原型链污染漏洞详解
一、JavaScript原型链基础
1.1 原型链概念
JavaScript通过原型链实现继承机制。每个对象都有一个原型对象(__proto__),原型对象也可能有自己的原型,形成原型链。
1.2 关键术语
- prototype:函数的原型属性,只有函数拥有
- proto:实例对象的原型指针,指向构造函数的prototype
- constructor:指向构造函数本身
1.3 原型链示例
function Person(name, age) {
this.name = name;
this.age = age;
}
const p = new Person('zhangsan', 18);
// 原型关系
f.constructor === Foo;
f.__proto__ === Foo.prototype;
Foo.__proto__ === Function.prototype;
二、原型链污染原理
2.1 基本概念
通过修改实例对象的__proto__中的值,污染类本体,进而影响所有和该对象来自同一个类、父祖类的对象。
2.2 污染条件
需要满足以下条件:
- 能够控制对象属性
- 能够将
__proto__作为键名传入 - 存在对象合并、克隆或属性修改操作
2.3 污染示例
function merge(target, source) {
for (let key in source) {
if (key in source && key in target) {
merge(target[key], source[key])
} else {
target[key] = source[key]
}
}
}
let o1 = {}
let o2 = JSON.parse('{"a": 1, "__proto__": {"b": 2}}')
merge(o1, o2)
let o3 = {}
console.log(o3.b) // 输出2,原型已被污染
三、实际利用场景
3.1 常见易受攻击操作
- 对象合并(merge):将多个对象属性合并到一个对象中
- 对象克隆(clone):实质是将对象merge到空对象中
- 路径查找属性修改:通过路径查找并修改属性
3.2 关键点
- 直接使用
{__proto__: {...}}语法不会触发污染,因为__proto__会被解释为原型 - 通过
JSON.parse解析的__proto__会被视为普通键名,可实现污染
四、实际漏洞分析:CVE-2019-11358
4.1 漏洞描述
jQuery 3.4.0之前版本存在原型污染漏洞,通过jQuery.extend()函数可实现污染。
4.2 漏洞利用
const json1 = '{"__proto__": {"z": 123}}';
jQuery.extend(true, {}, JSON.parse(json1));
// 验证污染
console.log({}.z); // 输出123
4.3 漏洞原理
jQuery.extend()进行深度合并时,未对__proto__进行特殊处理,导致可以修改Object原型。
五、防御措施
- 避免使用不安全的合并函数:使用Object.assign等安全方法
- 冻结Object.prototype:
Object.freeze(Object.prototype) - 检查键名:在合并操作前检查
__proto__、constructor等敏感属性 - 使用无原型对象:
Object.create(null)创建无原型的对象 - 升级依赖库:及时更新存在漏洞的第三方库
六、总结
JavaScript原型链污染是一种通过修改原型链实现污染全局对象的漏洞,主要出现在对象合并、克隆等操作中。理解原型链机制是防御此类漏洞的基础,开发者应特别注意对用户输入的处理,避免将不可信数据直接用于对象操作。