【无标题】

原型链污染漏洞

前言

深入了解javascript

对象与类

JavaScript一切都是对象,我们先来了解对象

创建一个简单的js对象如下:

var obj ={};

创建obj这个对象师,并没有赋予它任何的属性和方法,但是他会具有一些内置属性和方法,像是__proto__,constructor,toString等。

为了探究这些内置属性是怎么来的,我们需要看一下JavaScript中类的一些机制,JavaScript中的类是从一个函数开始的;

函数对象:

function MyClass(){
      console.log("qaq");
}
var inst = new MyClass();
//以上代码创建了一个MyClass函数,同时MyClass也是一个类,可以像别的语言中那样为这个类实例化一个对象inst

以上代码的执行结果,在实例化inst时候,MyClass()也同样执行了

这可以联想带构造函数,构造函数的特性就是在new一个对象的时候执行

所以MyClass()函数与MyClass这个类的关系是前者是后者的构造函数

通过constructor这个属性还可以查看对象的构造函数

__proto__与prototype

prototype是一个类的属性,所有类对象在实例化的时候将会拥有prototype中的属性和方法

类在运行运行时是可以修改的

function test (){
      this.a = "test";}
undefined
b = new test;
test{a:"test"}

console.log(b.a);
test

可以看到b在实例化为test对象以后,就可以输出test类中的属性a了。这是为什么?

原因在于js中一个重要的概念:继承

而继承的整个过程就成为该类的原型链。

//在javascript中,每个对象的都有一个指向他的原型(prototype)的内部链接,这个原型对象又有它自己的原型,直到null为止
function i(){
    this.a = "test1";
    this.b = "test2";}

可以看到其父类为object,且里面还有许多函数,这就解释了为什么许多变量可以调用某些方法。

在javascript中一切皆对象,因为所有的变量,函数,数组,对象 都始于object的原型即object.prototype。同时,在js中只有类才有prototype属性,而对象却没有,对象有的是__proto__和类的prototype对应。且二者是等价的

>function Foo(){
      this.bar =1;
}
<undefined
>Foo.prototype.show = function show ()
       console.log(this.bar);}
<show (){
       console.log(this.bar0:}
>let foo +new Foo
<undefinde
>Foo.prototype;
<{show:f,constructor:f}
>foo.__proto__
<{shwo:f,constructor;f}
>Foo.prototype -- foo.__proto__
<true

了解原型链

当我们创建一个类的时候,原型链为b ->a.prototype ->object.prototype ->null

数组

当我们创建一个数组的时候,原型链为c ->array.prototype ->object.prototype ->null

函数

当我们创建一个函数时,原型链为d ->function.prototype ->object.prototype ->null

日期

当我们创建一个日期时,原型链为f ->Data.prototype -> object.prototype ->null

原型链变量搜索

>function g (){
         this.a ="test1";
         this.b ="test2";}
<undefined
>g.prototype.c ="test3";
<"test3"
>function i(){
          this.a ="test1";
          this.b ="test2";}
<undefined
>var j = new(i);
<undefined
>i.prototype.c = "test3";
<"test3"
>console.log(j.c);
test3

在实例要先于在i中添加属性,但是在j中也有了c属性。

这是为什么?

当要使用或输出一个变量时:首先会在本层中搜索相应的变量,如果不存在的话,就会向上搜索,即在自己的父亲中搜索,当父类目录中也没有时,就会向祖父类搜索,知道指向null,如果此时还没有搜索到,就会返回undefined

小总结

1JavaScript是一个神奇的语言,一切皆对象

2对象都有一个__proto__属性,指向它的类的”prototype"

3类是通过函数来定义的,定义的这个函数又是这个类的constructor属性值

4每个构造函数constructor都有一个原型对象prototype

5JavaScript使用prototype链实现继承机制

6子类是可以通过prototype链修改其父类属性,以及爷爷类的属性值

原型链污染

小实验

// foo是一个简单的JavaScript对象
let foo = {bar: 1}

// foo.bar 此时为1
console.log(foo.bar)

// 修改foo的原型(即Object)
foo.__proto__.bar = 2

// 由于查找顺序的原因,foo.bar仍然是1
console.log(foo.bar)

// 此时再用Object创建一个空的zoo对象
let zoo = {}

// 查看zoo.bar
console.log(zoo.bar)

zoo.bar的结果是2;

因为前面修改了foo的原型foo.__proto__.bar = 2,而foo是一个Object类的实例,所以实际上是修改了Object这个类,给这个类增加了一个属性bar,值为2。

后来,又用Object类创建了一个zoo对象let zoo = {},zoo对象自然也有一个bar属性了。

那么,在一个应用中,如果攻击者控制并修改了一个对象的原型,那么将可以影响所有和这个对象来自同一个类、父祖类的对象。这种攻击方式就是原型链污染。

原型链会被污染的情况

第一种
obj[a][b] = value
obj[a][b][c] = value

如果控制了a,b,c及value就可以进行原型链污染的攻击

可以控制a=__proto__

第二种
merge (target, source)
	foreach property of source
		if property exists and is an object on both the target and the source
			merge(target[property], source[property])
		else
			target[property] = source[property]

这种情况下,__proto__必须被视为key才能成功

对于

function merge(target, source) {
    for (let key in source) {
        if (key in source && key in target) {
            merge(target[key], source[key])
        } else {
            target[key] = source[key]
        }
    }
}
//1. 
let o1 = {}
let o2 = {a: 1, "__proto__": {b: 2}}
merge(o1, o2)
console.log(o1.a, o1.b)

o3 = {}
console.log(o3.b)//undefined

//2. 
let o1 = {}
let o2 = JSON.parse('{"a": 1, "__proto__": {"b": 2}}')
merge(o1, o2)
console.log(o1.a, o1.b)

o3 = {}
console.log(o3.b)//2

1和2两种情况是不一样的.

因为前面代码中 __proto__已经代表o2的原型了 ,没有被看成一个key

后面的代码中经过JSON.parse解析,__proto__就代表了一个key

补充
merge 

递归合并JavaScript对象中的值,深合并递归,将源的属性合并到目标中

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Rek'Sai

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值