什么是原型链?
由于_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
如果需要更加详细的叙述,请查找相关资料,本文只是对原型链及原型链污染的简单概述。
Comments | NOTHING