原型链污染
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 许可协议。转载请注明出处!