Prototype pollution是一个老生常谈的问题了;JavaScript是一门非常灵活的语言,在某些方面可能比PHP更加灵活。所以,除了一些sql注入和代码执行等注入型漏洞外,也会有一些独有的安全问题,比如prototype polllution。
说javascript灵活是因为一般的OOP语言会使用class关键字进行模版的定义,从这个class去实例化的对象都会自然的继承了模版中相应的属性;但是javascrip可以支持直接定义一个对象;大可不必要提前定义模版;
可以鲜明的看到直接定义了一个对象,当去尝试new的时候会抛出错误“不是构造器”;当然也可通过构造函数去定义一个模版,后期可以批量的实例化对象;
比如如下的代码定义一个类;用“构造函数”定义一个模版,后期可以批量的实例化对象;
1 | function s1mple(){ |
定义了一个s1mple构造器,相当也定义了一个class;其中test和work是属性;
可以看到效果是等效的;
每一个函数对象都会有一个prototype属性;指向它实例化的原型;使用该构建函数实例化对象时,会继承该原型中的属性及方法。
__proto__:
所有对象都有一个__proto__
属性;它指向了构建它的函数的原型;即:s1mple.prototye==c.__proto__
函数的prototype是原型对象;原型对象也是普通对象;所以也一般实例一样,也具有__proto__
属性;
原型对象的constructor属性指向和它相关联的构造函数;
javascript的继承机制就是由原型链来实施的;比如如下的代码;
可以看到,我们将s2mple构建函数的prototype设置成s1mple对象,此时s2mple就会继承了s1mple对象的属性;其实本质就是,将s2mple的原型设置成s1mple对象,当在s2mple对象中调用某个属性的时候如果在s2mple中没有找到,则会去自动触发s2mple对象的__proto__
去原型里去寻找,这里设置成了s1mple,所以就直接到s1mple对象中找;最后返回s1mple对象中的值;通过原型链将两个类对象进行串联,使其有继承关系;以此类推直到Object.prototype的__proto__
就是null;
js通过原型链索引一个对象的属性和方法,上面了解了原型;分析了其机制;那么就会产生一个问题;如果可以给某些类的原型加上某些属性或者方法;那么继承它的对象就都会有此属性或者方法;如果给Object加上的话,那么所有的对象都会受到污染;这样就可以覆盖某些变量,实际中可绕过某些验证;
1 | var cc = {"a":"b"} |
这里可以清晰的看到用原来的对象去访问相应的c属性;会到相应的原型下去进行访问获取;那么如果再次实例化对象的时候因为原型对象已经被插入恶意数据,那么新对象也会被污染,具体看下图:
可以看到已经被污染;