JS原型链污染

发布于 2023-09-09  294 次阅读


什么是原型链?

由于_proto_属性是任何对象都拥有的属性,而在JS中,万物皆对象,因此,会形成一条_proto_连接起来的链条,递归访问_proto_必须最终到头,并且值为null。当JS引擎查找对象属性时,会先查询该对象是否存在该属性,如果不存在,那么就会在原型链上查找,但是并不会查找自身的prototype。

prototype和_proto_的用法与区别

对象._proto_ = 构造器(构造函数).prototype。构造器.prototype其实也是一个对象,因此,其也拥有构造器.prototype._proto_的属性,而这个属性又等于另一个构造器.prototype。所以在这样的情况下就形成了一条原型链,直到最终找到null。

而对象._proto_和构造器.prototype都是访问类的原型的。

所以,prototype是一个类的属性,所有类对象在实例化的时候都会拥有prototype中的属性和方法。一个对象的_proto_属性,会指向这个对象所在类的prototype方法。

用一个简单的图来描述就是:

而该特性也被用来实现js中的继承机制。

例如存在两个类,Father类和Son类,那么通过代码:Son.prototype = new Father();//其中Son.prototype的意思就是Son的父类。Son类就可以继承Father类中的所有属性。

而在JS引擎中,其寻找属性的过程就是,首先在Son类中寻找相关属性,如果没有相关属性,就会在son._proto_中寻找相关属性,如果还是找不到,就会在son._proto_._proto_中找寻相关属性,直到最后找到null。

原型组成的链:对象的__proto__是原型,而原型也是一个对象,也有__proto__属性,原型的__proto__又是原型的原型,就这样可以一直通过__proto__向上找,这便是原型链,当向上找找到Object的原型的时候,这条原型链便算结束了。

拥有了上述对于原型链的介绍,那么什么是原型链污染呢?

我们做一个假设,如果foo._proto_指向Foo类的prototype,那么,如果我们修改_proto_中的值,那么是不是就可以对Foo类中的值进行修改呢。

let foo = {bar:1}
foo.bar = 1

foo._proto_.bar = 2
foo.bar = 1

let zoo = {}

我们获取zoo.bar的值,我们会惊奇的发现,zoo.bar = 2,而我们在代码中zoo是一个空对象。那么为什么会显示zoo.bar = 2呢。

其实,是因为前面我们修改了foo._proto_.bar的值为2,而foo是Object类的实例,那么实际上我们是修改了类Object,在Object类中增加了bar属性。而后面我们就创建了一个Object的实例zoo,那么zoo对象就自然也存在一个bar属性,其值为2。(这种变化并不会影响已经创建的对象,而会影响后面新创建的对象)。

所以,在应用中,如果攻击者控制了一个对象的原型,那么就可以影响所有和这个对象来自相同类、父类、父类的父类等等的对象了,这样的攻击方式就叫做原型链污染。

那么什么情况下会发生原型链污染呢?

就是当我们对JSON格式的键值对进行解析的时候,即调用JSON.parse的时候,_proto_就会被当做键名,在这种时候,利用_proto_就可以进行原型链污染。

具体参考:https://blog.csdn.net/qq_51586883/article/details/119867720?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522169417539216800222866535%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=169417539216800222866535&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduend~default-1-119867720-null-null.142^v93^koosearch_v1&utm_term=%E5%8E%9F%E9%93%BE%E5%9E%8B%E6%B1%A1%E6%9F%93&spm=1018.2226.3001.4187

如果需要更加详细的叙述,请查找相关资料,本文只是对原型链及原型链污染的简单概述。


一花一世界,一叶一菩提。