JS原型链污染

JS原型链污染

原理

JavaScript中,类以构造函数的方式来进行定义,test函数的内容就是test类的构造函数,test1是test类的一个实例对象,this.a是test类的一个属性。

JS原型链

JavaScript中,每定义一个函数数据类型,都会自带一个prototype属性,这个属性指向函数的原型对象,并且这个属性是一个对象数据类型的值。

1
2
3
4
5
6
7
8
9
10
11
12
13
function Father() {
this.first_name = 'AAAA'
this.last_name = 'BBBB'
}

function Son() {
this.first_name = 'CCCC'
}

Son.prototype = new Father()

let son = new Son()
console.log(`Name: ${son.first_name} ${son.last_name}`)

Son类继承了Father类中的last_name,覆盖了Father类中的first_name。son是Son类的一个实例化对象。Son类的原型prototype指向了Father类。

1
2
3
实例对象 son.__proto__ 相当于 类 Son.prototpye 具有等价关系,都指向了Father类

Son类的实例化对象 son可以通过son.__proto__来访问Son类的原型

1
2
原型链:son.__proto__->Son.prototype->Father.prototype->Object.prototype->NULL
形成一条由__proto__ 连接起来的链条

当我们使用一个变量时,该类首先会检测自身,如果不存在,则会沿着原型链递归查找,直到指向NULL。

JS原型链污染

son.__proto__指向的是Son类的prototype。如果我们修改了son.__proto__中的值,就可以修改Son类

我们修改了实例化对象son在原型链中的对应的son.__proto__ .__proto__ .__proto__,实际上是修改了Object这个类,给这个类增加了一个属性test。

当我们用Object类创建了一个test空对象时,该对象就直接含有了一个test属性。

实例

国赛

国赛的时候一道原型链污染的题目

核心代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
function  getPlayerDamageValue() //计算纯粹伤害
{
if (player.buff) {
return keepTwoDecimal(player.aggressivity+player.buff)
} else return player.aggressivity
}

app.post('/start', (req, res) => {
if (req.body && typeof req.body== 'object' )
{
player = {
name : "ciscn",
career : "warrior",
item : "BYZF",
round_to_use : 1 //round_to_use表示在哪一轮使用物品
}

let tempPlayer = req.body

for ( let i in tempPlayer )// i就是遍历的时候用的键值
{
if (player[i]) {
if ( (i == 'career' && !careers.includes(tempPlayer[i])) || (i == 'item' && !items.includes(tempPlayer[i])) || (i == 'round_to_use' && !checkRound(tempPlayer[i])) || tempPlayer[i] === '') {
continue
}
player[i] = tempPlayer[i]
}
}
player.num = 1; //player剩余可`使用物品`的次数
player.HP = 100; //HP为血量
player.aggressivity = getPlayerAggressivity()

initMonster()
res.redirect("/battle")
} else {
res.redirect("/")
}
})

我们就可以通过构造req.body进行原型链污染,在实例化对象tempPlayer的原型__proto__指向的Object类中加入buff属性,__proto__可以作为查找键值

其他

哪些情况下我们可以设置__proto__的值呢?能够控制数组(对象)的“键名”的操作:

  • 对象merge
  • 对象clone(其实内核就是将待操作的对象merge到一个空对象中)

咕~

0%