0%

JavaScript原型链污染

JavaScript原型链污染

大力学习js然后学到原型链把人学傻了,专门理了一下

__proto__和prototype

每个对象都存在一个__proto__属性,而每个类(js并没有很正统的类这个说法)则拥有prototype,由该类构造出来的对象的__proto__就指向该类的prototype,这都是网上可以搜到的内容,不想讲,看这个
https://www.cnblogs.com/shuiyi/p/5305435.html

主题

今天主要是想解决一下常见原型链污染时出现的困惑
常见都是先使用{"a": 1, "__proto__": {"b": 2}}这个payload再使用merge之类的函数合并进行原型链污染,而又由此牵扯出这样子创建变量导致__proto__直接被认定为属性,merge函数无法取得,需要用JSON.parse将其解析为键值进行污染。
我就在想,既然我已经创建出了这样子的一个对象,为什么没有直接污染原型链呢

>o1 = {"__proto__":{"b": 1}}
<{}
>o2 = {}
<{}
>o2.b
<undefined
>o1.__proto__
<{b: 1}
    b: 1
    __proto__: Object

这里使用这样子的方式进行赋值,__proto__的确是一个属性而不是一个键值对,但是__proto__[b]=1却并没有污染到原型链,按照我一开始的理解,这样子应该是直接修改了object的prototype的,因为o1.__proto__===Object.prototype,但事实上,这个方式事实上是像下面这种赋值语句一样,把o1的__proto__赋值给了其他对象,并没有取得Object的prototype

>b = {"c":2}
<{c: 2}>o1 = {}
<{}>o1.__proto__ 
<{constructor: ƒ, __definegetter__: __definesetter__: hasownproperty: __lookupgetter__: ƒ, …}>o1.__proto__ = b
<{c: 2}>o1.__proto__ 
<{c: 2 2} c: __proto__: object < code>

而对于如下这种形式可以污染原型链,是因为修改的是__proto__下的一个属性,并不是修改__proto__的内容

>o2 = {}
<{}
>o2.__proto__.aaa = 1
<1
>o3 = {}
<{}
>o3.aaa
<1

__proto__就像是一个指向原型的指针,你令__proto__=a的时候,直接修改了这个指针的指向,自然不会影响到原型,而你使用__proto__.a=1时,则是通过这个指针直接修改了其指向的原型中的属性