原型链污染是指攻击者通过修改JavaScript对象的原型(prototype),从而影响了基于该原型创建的所有对象的行为。
 
在JavaScript中,每个对象都有一个指向其原型的内部链接,这个原型本身也可以有它自己的原型,形成了一条原型链。
 当访问一个对象的属性时,如果该对象自身没有这个属性,JavaScript引擎会沿着原型链向上查找。
什么是原型链污染
例如之前讲的原型案例:
// 假设我们有一个名为 Alice 的对象,它有一个 greet 方法  
let Alice = {  
    greet: function() {  
        console.log("Hello, I'm Alice.");  
    }  
};  
  
// Alice 调用 greet 方法,输出 "Hello, I'm Alice."  
Alice.greet(); // 输出: Hello, I'm Alice.  
  
// 接下来,攻击者试图通过修改 Alice 的原型来污染原型链  
Alice.__proto__.evilGreet = function() {  
    console.log("You've been hacked!");  
    // 这里可以执行更多的恶意代码...  
};  
  
// 攻击者现在创建了一个新的对象 Bob,它基于 Object.prototype(即 Alice 的原型)  
let Bob = {};  
  
// Bob 调用 evilGreet 方法,这是通过原型链污染注入的  
Bob.evilGreet(); // 输出: You've been hacked!  
  
// 更糟糕的是,由于原型链污染,现在所有基于 Object.prototype 创建的对象都继承了这个恶意的 evilGreet 方法  
// 包括 Alice 对象本身(尽管它原本有自己的 greet 方法)  
Alice.evilGreet(); // 输出: You've been hacked!
 
在这个案例中,攻击者通过向 Alice.__proto__(即 Object.prototype)添加一个新的 evilGreet 方法,成功地污染了原型链。
 这不仅影响了新创建的对象 Bob,还影响了原有的 Alice 对象。
 即使 Alice 对象原本有自己的 greet 方法,它现在也能访问到通过原型链污染注入的 evilGreet 方法。
不安全的对象合并
在实际应用中,哪些情况下可能存在原型链能被攻击者修改的情况呢?
 我们思考一下,哪些情况下我们可以设置_proto__的值呢?其实找找能够控制数组(对象)的“键名”的操作即可:
 。对象merge 结合 拼接
 。对象clone(其实内核就是将待操作的对象merge到一个空对象中)复制以对象merge为例,我们想象一个简单的merge函数:
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];
        }
    }
}
// 假设有一个用户输入的对象  
const userInput = {
  "name":"alice",
  __proto__: {  
    isAdmin: true  
  }  
};  
// 合并对象时,原型链被污染  
merge({}, userInput);  
// 所有对象都会继承这个isAdmin属性  
console.log({}.isAdmin); // 输出: undefined
 
实际上Object输出的是undefined,这是因为,我们用lavaScript创建userInput的过程const userInput = { ... }中,__proto__已经代表userInput的原型了,
 此时遍历userInput的所有键名,你拿到的是[name],__proto__并不是一个key自然也不会修改Object的原型。
 现在将代码改成:
let userInput =JSON.parse('{"name":"alice","__proto__":{"isAdmin":true}}')
// 合并对象,导致原型链污染  
merge({}, userInput);  
// 正常来说所有对象都会继承这个isAdmin属性  
console.log({}.isAdmin); // 输出: true
 
这样的话alice对象的原型就被污染了,所有继承自Object.prototype的对象都将具有isAdmin属性 。
总结
系列文章
蓝桥杯-网络安全比赛(5)基础学习-JavaScript原型链
 蓝桥杯-网络安全比赛(4)基础学习-JavaScript同步与异步、宏任务与微任务
 蓝桥杯-网络安全比赛(3)基础学习- JavaScript的闭包与this
 蓝桥杯-网络安全比赛(2)基础学习-正则表达式匹配
 蓝桥杯-网络安全比赛(1)基础学习-使用PHP、PYTHON、JAVA









