CVE-2019-11358分析
字数 1481 2025-08-29 08:32:24
JavaScript原型链污染漏洞分析与防御(CVE-2019-11358)
一、JavaScript原型基础
1. JavaScript的类与实例
- 在JavaScript中,构造函数相当于类,通过
new关键词或Object.create()方法创建实例 - 示例:
function Func() {
this.demo = 1;
}
var func = new Func();
2. prototype与__proto__
-
prototype属性:
- 所有JavaScript函数都有一个
prototype属性,指向该构造函数的原型 - 例如
Func.prototype指向Func的原型
- 所有JavaScript函数都有一个
-
__proto__属性:
- 所有JavaScript实例对象都有一个
__proto__属性,指向其实例对象的原型 - 例如
func.__proto__指向func的原型
- 所有JavaScript实例对象都有一个
-
关系总结:
- 实例对象的
__proto__指向构造函数的prototype - 原型链终点为
null(Object.prototype.__proto__ === null)
- 实例对象的
二、JavaScript原型链机制
1. 原型链结构
- 示例原型链:
func -> Func.prototype -> Object.prototype -> nullarray -> Array.prototype -> Object.prototype -> nulldate -> Date.prototype -> Object.prototype -> null
2. 继承查找过程
-
属性查找顺序:
- 对象自身属性
- 对象的
__proto__(构造函数的prototype) - 递归查找
__proto__.__proto__直到null
-
继承示例:
function Father() {
this.first_name = 'Tome';
this.last_name = 'Alpha';
}
function Son() {
this.first_name = 'Lisa';
}
Son.prototype = new Father();
let son = new Son();
console.log(`Name: ${son.first_name} ${son.last_name}`);
// 输出:Name: Lisa Alpha
三、原型链污染机制
1. 基本原理
- 通过控制对象属性名(特别是
__proto__)和赋值操作,修改原型链上的属性 - 影响范围:所有来自同一类、父祖类的对象
2. 污染条件
- 对象/数组的键名或属性名可控
- 存在赋值操作
3. 常见场景
- 对象合并(merge)操作
- 对象克隆(clone)操作
4. 污染示例
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 demo1 = {};
let demo2 = JSON.parse('{"name": "h3", "__proto__": {"age": 20}}');
merge(demo1, demo2);
console.log(demo1.name, demo1.age); // h3 20
let demo3 = {};
console.log(demo3.age); // 20(污染成功)
四、CVE-2019-11358漏洞分析
1. 漏洞信息
- 影响版本:jQuery < 3.4.0
- 漏洞类型:原型污染
- 危害:可能导致拒绝服务或代码执行
2. 漏洞原理
- jQuery的
extend函数在深拷贝模式下未正确处理__proto__属性 - 攻击者可注入恶意属性污染Object原型
3. 关键代码分析
jQuery.extend = jQuery.fn.extend = function() {
var options, name, src, copy, copyIsArray, clone,
target = arguments[0] || {},
i = 1,
length = arguments.length,
deep = false;
// 深拷贝模式判断
if(typeof target === "boolean") {
deep = target;
target = arguments[i] || {};
i++;
}
// 遍历参数
for(; i < length; i++) {
if((options = arguments[i]) != null) {
// 遍历属性
for(name in options) {
src = target[name];
copy = options[name]; // 外部可控
// 深拷贝处理
if(deep && copy && (jQuery.isPlainObject(copy) ||
(copyIsArray = Array.isArray(copy)))) {
// 递归处理对象或数组
target[name] = jQuery.extend(deep, clone, copy);
} else if(copy !== undefined) {
// 直接赋值
target[name] = copy;
}
}
}
}
};
4. 漏洞利用
- PoC:
$.extend(true, {}, JSON.parse('{"__proto__": {"exploit": "h3rmesk1t"}}'));
console.log(exploit); // 输出"h3rmesk1t"
- 复现步骤:
var jquery = document.createElement('script');
jquery.src = 'https://code.jquery.com/jquery-3.3.1.min.js';
let exp = $.extend(true, {}, JSON.parse('{"__proto__": {"exploit": "h3rmesk1t"}}'));
console.log({}.exploit); // 输出"h3rmesk1t"
五、防御措施
1. 官方修复方案
- jQuery 3.4.0+版本增加了对
__proto__属性的检查 - 修复方式:检测到
__proto__属性时跳过合并
2. 开发建议
- 避免使用不安全的对象合并/克隆操作
- 对用户输入的JSON数据进行严格过滤
- 检查对象属性名是否包含敏感键(如
__proto__、constructor等) - 使用
Object.create(null)创建无原型的对象
3. 安全编码示例
// 安全的merge函数
function safeMerge(target, source) {
for(let key in source) {
if(key === '__proto__' || key === 'constructor' || key === 'prototype') {
continue; // 跳过敏感键
}
if(key in source && key in target) {
safeMerge(target[key], source[key]);
} else {
target[key] = source[key];
}
}
}
六、总结
JavaScript原型链污染是一种通过修改对象原型链来影响所有相关对象的安全漏洞。CVE-2019-11358展示了jQuery在对象深拷贝时未正确处理__proto__属性导致的严重安全问题。开发者应当:
- 及时更新依赖库到安全版本
- 避免直接使用不受信任的JSON数据
- 实现安全的对象操作函数
- 了解原型链机制,编写防御性代码
通过理解原型链机制和污染原理,开发者可以更好地预防此类安全问题,构建更安全的JavaScript应用。