WEB安全
00-HTTP协议
01-前端基础【HTML】
02-前端基础【CSS】
03-后端基础【PHP速通】
04-后端基础【PHP面向对象】
05-MySQL基础操作
06-前后端联动【代码练习】
07-SQL注入
08-SQL注入 Labs
09-跨站脚本攻击【XSS】
09-XSS Labs
10-CSRF
11-SSRF
12-XML 外部实体注入【XXE】
13-代码执行漏洞
14-命令执行漏洞
15-文件包含漏洞
16-文件上传漏洞
17-反序列化漏洞
18-业务逻辑漏洞
19-未授权访问漏洞集合
20-跨源资源共享【CORS】
21-SSTI模板注入
22-并发漏洞
23-点击劫持【Clickjacking 】
24-请求走私
25-路径遍历
26-访问控制
27-身份验证漏洞
28-WebSocket
29-Web缓存中毒
30-HTTP 主机头攻击
31-信息泄露漏洞
32-原型污染
33-API概述
34-API分类类型
35-API交换格式
36-API身份验证
37-API常见漏洞
38-crAPI靶场
39-JWT
40-DVGA靶场
41-服务器端参数污染
42-API Labs
43-OAuth Labs
44-GraphQL API Labs
45-JWT Labs
46-小程序抓包
47-云存储
48-对象存储OSS
49-存储桶
50-存储桶漏洞
51-STS访问OSS
-
+
32-原型污染
浏览
1
要理解原型污染(Prototype Pollution),首先需要掌握 JavaScript 的原型(Prototype)与原型链(Prototype Chain) 机制 —这是 JS 实现继承的核心,也是原型污染产生的根源。 ## JS 的原型与原型链 在 JS 中,几乎所有对象都是通过构造函数创建的,而每个构造函数都有一个 prototype 属性(原型对象);同时,每个实例对象都有一个隐式的 [[Prototype]] 指针(可通过 \__proto__ 访问,非标准但浏览器普遍支持),指向其构造函数的 prototype。 当访问一个对象的属性时,JS 会先在对象自身查找;若找不到,则沿着 [[Prototype]] 向上遍历原型链,直到找到属性或遍历到顶层的 Object.prototype(其 [[Prototype]] 为 null)。 例如: ```javascript // 1. 构造函数 function Person(name) { this.name = name; // 实例自身属性 } // 2. 给构造函数的原型添加方法(所有实例共享) Person.prototype.sayHi = function() { console.log(Hi, ${this.name}); }; // 3. 创建实例 const alice = new Person("Alice"); alice.sayHi(); // 输出 "Hi, Alice" // 原理:alice 自身没有 sayHi,沿 alice.__proto__ → Person.prototype 找到 sayHi // 4. 顶层原型:Object.prototype console.log(alice.toString()); // 输出 "[object Object]" // 原理:alice.__proto__.__proto__ → Object.prototype,toString 是 Object.prototype 的方法 ``` 所以: - 所有对象最终都继承自 Object.prototype(除非用 Object.create(null) 创建无原型对象)。 - 若修改某个原型对象(如 Object.prototype),则所有继承自该原型的对象都会受到影响—— 这正是原型污染的关键。 ## 什么是原型污染? 原型污染是指:攻击者通过未授权的方式,修改了对象的原型(尤其是顶层原型 Object.prototype),导致所有继承自该原型的对象都被 “污染”,从而引发一系列安全问题或逻辑漏洞。 简单来说,就是利用 JS 原型链的特性,强行给原型对象注入恶意属性或方法,让所有依赖该原型的对象 “被动继承” 这些恶意内容。 ## 实现方式 原型污染的核心是修改原型对象的属性,常见途径有 3 种: 1. 通过 \__proto__ 直接修改 \__proto__ 是实例对象访问其原型的 “入口”,若攻击者能控制对象的键名(如用户输入作为键),就可以通过 obj["\_\_proto\__"] 或 obj.\_\_proto__ 直接修改原型。 示例:污染 Object.prototype ```javascript // 1. 初始状态:空对象没有 isAdmin 属性 const normalObj = {}; console.log(normalObj.isAdmin); // 输出 undefined // 2. 攻击者通过 __proto__ 污染 Object.prototype const attackObj = {}; attackObj.__proto__.isAdmin = true; // 等价于 Object.prototype.isAdmin = true // 3. 所有对象(继承自 Object.prototype)都被污染 console.log(normalObj.isAdmin); // 输出 true(原本没有,现在从原型继承) const anotherObj = new Array(); // 数组也继承自 Object.prototype console.log(anotherObj.isAdmin); // 输出 true ``` 2. 通过 prototype 属性修改 构造函数的 prototype 属性直接指向原型对象,若攻击者能控制构造函数,可通过 Constructor.prototype 修改原型。 示例:污染 Array.prototype ```javascript // 攻击者修改 Array 的原型,注入恶意方法 Array.prototype.stealData = function() { console.log("窃取数组数据:", this); }; // 所有数组实例都被动继承该方法 const myArray = [1, 2, 3]; myArray.stealData(); // 输出 "窃取数组数据:[1,2,3]" ``` 3. 通过 Object.setPrototypeOf 方法 Object.setPrototypeOf(target, proto) 是 JS 标准方法,用于设置 target 的原型为 proto。 若 target 是原型对象,或 proto 包含恶意内容,会导致污染。 ```javascript const maliciousProto = { backdoor: true }; // 将 Object.prototype 的原型设为恶意原型(虽不常见,但可污染) Object.setPrototypeOf(Object.prototype, maliciousProto); const testObj = {}; console.log(testObj.backdoor); // 输出 true(沿原型链找到 maliciousProto) ``` ## 危害 原型污染的危害程度取决于攻击场景,轻则破坏应用逻辑,重则配合其他漏洞实现远程代码执行(RCE)。 1. 篡改全局数据 / 权限 如示例中污染 Object.prototype.isAdmin = true,可能导致应用误判所有用户为 “管理员”,绕过权限检查。 2. 破坏应用逻辑 若污染 Object.prototype.toString 等原生方法,会导致依赖这些方法的功能失效: ```javascript // 污染 toString 方法 Object.prototype.toString = function() { return "被篡改了!"; }; console.log([1,2,3].toString()); // 输出 "被篡改了!"(原本应为 "1,2,3") console.log(new Date().toString()); // 输出 "被篡改了!"(原本应为日期字符串) ``` 3. 配合漏洞实现 RCE 原型污染本身不直接执行代码,但可作为 “前置漏洞”,结合其他特性(如 eval、Function 构造函数、模板字符串注入等)触发 RCE。 例如,若应用中有如下代码(使用用户输入动态执行函数): ```javascript function execute(code) { return eval(code); // 危险:直接执行字符串代码 } // 攻击者污染 Object.prototype,注入恶意代码 Object.prototype.payload = "console.log('恶意代码执行')"; // 若应用中存在代码拼接(如 execute("obj.payload")),则会执行恶意代码 execute("this.payload"); // 输出 "恶意代码执行" ``` 4. 绕过安全机制 部分安全工具(如 XSS 过滤器)依赖原生对象方法,原型污染可能导致过滤器失效,间接助长其他攻击。 ## 攻击场景 原型污染通常发生在用户输入能直接控制对象键名或属性赋值的场景,常见场景包括: | 场景 | 原理 | | ----------------- | ------------------------------------------------------------ | | 不安全的对象合并 | 如使用 $.extend(true, target, source)(jQuery 旧版本)、自定义 merge 函数,若 source 包含 __proto__ 键,会污染原型。 | | 序列化 / 反序列化 | 如 JSON.parse 配合 reviver 参数、unserialize 函数(如 PHP-JS 交互时),攻击者可构造包含 __proto__ 的序列化数据。 | | 用户输入作为键名 | 如 obj[userInputKey] = userInputValue,若 userInputKey 为 __proto__,则修改原型。 | | 第三方库漏洞 | 历史上多个知名库存在原型污染漏洞(如 Lodash < 4.17.19、jQuery < 3.4.0、Moment.js 等),攻击者可利用库的接口触发污染。 | ## 防护措施 防御的核心是阻止未授权的原型修改,针对不同场景可采取以下措施: 1. 过滤敏感键名 若用户输入作为对象键名,需过滤 __proto__、prototype 等敏感关键词,避免修改原型: ```javascript function safeSet(obj, key, value) { // 过滤敏感键,直接忽略或报错 if (key === "__proto__" || key === "prototype") { throw new Error("非法键名!"); } obj[key] = value; } const obj = {}; safeSet(obj, "__proto__", { isAdmin: true }); // 抛出错误,避免污染 ``` 2. 使用 Object.create(null) 创建无原型对象 Object.create(null) 会创建一个没有任何原型的对象(其 [[Prototype]] 为 null),不会继承 Object.prototype,因此即使被污染也不会影响全局: ```javascript // 无原型对象,不受 Object.prototype 污染影响 const safeObj = Object.create(null); Object.prototype.isAdmin = true; console.log(safeObj.isAdmin); // 输出 undefined ``` 3. 禁止直接修改原型 避免使用 __proto__ 赋值(可通过 Object.freeze(Object.prototype) 冻结顶层原型,使其无法被修改): ```javascript // 冻结 Object.prototype,禁止添加/修改属性 Object.freeze(Object.prototype); Object.prototype.isAdmin = true; // 无效(严格模式下会报错) ``` 慎用 Object.setPrototypeOf,若必须使用,需严格校验 proto 参数。 4. 使用安全的对象合并方法 避免使用老旧版本的 jQuery($.extend(true) 存在漏洞),升级到最新版。 自定义 merge 函数时,需递归检查键名,跳过敏感键: ```javascript function safeMerge(target, source) { for (const key in source) { // 跳过敏感键,避免污染原型 if (key === "__proto__" || key === "prototype") continue; const targetVal = target[key]; const sourceVal = source[key]; // 若均为对象且非 null,递归合并(避免深污染) if (typeof targetVal === "object" && targetVal !== null && typeof sourceVal === "object" && sourceVal !== null) { safeMerge(targetVal, sourceVal); } else { target[key] = sourceVal; } } return target; } ``` 5. 及时更新依赖库 定期扫描项目依赖(如使用 npm audit),修复第三方库中的原型污染漏洞(如 Lodash、jQuery 等)。 6. 启用严格模式(Strict Mode) 在 JS 文件头部添加 "use strict";,严格模式下部分不安全操作(如意外修改原型)会直接报错,便于提前发现问题。
毛林
2026年11月15日 18:27
转发文档
收藏文档
上一篇
下一篇
评论(0)
登录
后可发表评论
还没有评论,来抢沙发~
手机扫码
复制链接
手机扫一扫转发分享
复制链接
Markdown文件
Word文档
PDF文档(打印)
分享
链接
类型
密码
更新密码
还没有评论,来抢沙发~