原型链污染
0x01 原型prototype
在js
中我们所创建的每一个函数,解析器都会向函数中添加一个属性prototype
,这个属性对应着一个对象,这个对象就是我们所谓的原型对象。如果函数作为普通函数调用prototype没有任何作用。原型对象就相当于一个公共的区域,所有同一个类的实例都可以访问到这个原型对象,我们可以将对象中公有的内容统一设置到原型对象中,当我们访问对象的一个属性或方法时,它会先在自身中寻找,如果有则直接使用,如果没有则会去原型对象中寻找,如果找到则直接使用。
1 | function MyClass(){ |
1 | function Foo() { |
但这样写有一个问题,就是每当我们新建一个Foo对象时,this.show = function...
就会执行一次,这个show
方法实际上是绑定在对象上的,而不是绑定在“类”中。
我希望在创建类的时候只创建一次show
方法,这时候就则需要使用原型(prototype)了:
1 | function Foo() { |
可以看到b
并没有a
属性,但是通过原型污染,使b
的可以访问到a
属性
0x02 JavaScript原型链继承
所有类对象在实例化的时候将会拥有prototype
中的属性和方法,这个特性被用来实现JavaScript中的继承机制。
1 | function Father() { |
Son
类继承了Father
类的last_name
属性,最后输出:Name:Kimi Tom
- 在对象
Son
中寻找last_name
- 找不到,继续在
Son.__proto__
中寻找last_name
- 如果仍找不到,则继续在
Son.__proto__.__proto__
中寻找last_name
- 依次寻找,直到找到
null
结束,Object.prototype
的__proto__
就是null
0x03 原型链污染
1 | // foo是一个简单的JavaScript对象 |
最后,虽然zoo是一个空对象{}
,但zoo.bar
的结果居然是2:
原因也显而易见:因为前面我们修改了foo的原型foo.__proto__.bar = 2
,而foo是一个Object类的实例,所以实际上是修改了Object这个类,给这个类增加了一个属性bar,值为2。
后来,我们又用Object类创建了一个zoo对象let zoo = {}
,zoo对象自然也有一个bar属性了。
那么,在一个应用中,如果攻击者控制并修改了一个对象的原型,那么将可以影响所有和这个对象来自同一个类、父祖类的对象。这种攻击方式就是原型链污染。
- 本文作者: y0lo
- 本文链接: http://example.com/2021/04/10/浅谈nodejs原型链污染/
- 版权声明: 本博客所有文章除特别声明外,均采用 MIT 许可协议。转载请注明出处!