闭包代码的提权漏洞
在开发中,我们经常会碰到使用闭包的场景,我们使用闭包的目的,是想要对一些数据进行保护来避免外界修改,有这么一个闭包函数,我们来看看它存在的漏洞
var o = (function(){
var obj = {
a: 1,
b: 2
};
return {
get(key) {
return obj[key]
}
}
})()
o.get('a') // 1
o.get('c') // undefined
很简单的一个闭包,就是访问当前对象的属性值,那么思考一下,如何在不改变上述代码的情况下,我们如何获取到闭包对象obj
的值呢?
valueOf
我们知道,对象的 valueOf
方法是返回其自身,我们来尝试看下
o.get('valueOf')() // Cannot convert undefined or null to object
执行代码后,我们发现,程序报错了,为啥呢?
我们来看下 valueOf
的大概实现过程
Object.prototype.valueOf = function() {
// ...
return this;
}
valueOf
的里的 this
取决于当前的调用对象,我们上述的代码可理解为这样
var obj = {
get() {
return this
}
}
var fn = obj.get;
fn(); // 指向了window
也就是说,o.get('valueOf')
只是拿到了其方法,执行时并没有指明 this
值
Object.defineProperty
我们来看下返回值 obj[key]
,通过这样的方式来返回对象的属性值,那么是否存在访问其属性值时返回其自身对象呢?例如访问某个属性时返回其自身。
我们知道 Object.defineProperty
的基本用法,需要给某个对象的某个属性做代理,那么前提是要知道需要代理的对象,这个好像又回到了开始的问题了,该给谁做代理呢?
访问对象的某个属性时,默认会先找自身,自身没有时会找其 原型链
上的属性。
由原型链作为突破口,我们可以给对象的原型链 Object.prototype
设置代理,代理其某个属性值(我们这里用 anyKey
),尝试去返回对象本身
Object.defineProperty(Object.prototype, 'anyKey', {
get() {
return this
}
})
o.get('anyKey') // {a: 1, b: 2} 拿到了闭包中的obj对象, o.get('anyKey')相当于obj['anyKey']
缺陷处理
通过 Object.defineProperty
可以访问到闭包里的obj对象,那么也就失去了闭包的意义了,那么如何处理这个缺陷呢?
断开原型链
我们在声明对象的时候,可以通过 Object.create(null)
和 Object.setPrototypeOf
来生成一个原型对象为 null
的对象,那么就无法访问其原型链上的属性。修改如下
var o = (function(){
var obj = {
a: 1,
b: 2
};
// 修改1
Object.setPrototypeOf(obj, null)
return {
get(key) {
return obj[key]
}
}
})()
var o = (function(){
// 修改2
var obj = Object.create(null);
obj.a = 1;
obj.b = 2;
return {
get(key) {
return obj[key]
}
}
})()
hasOwnProperty
如果不想断开原型链,那么我们可以校验其属性是否是对象自身所拥有的属性,来规避这个漏洞。我们则可以做这样的更改。
var o = (function(){
var obj = {
a: 1,
b: 2
};
return {
get(key) {
// 修改
if (obj.hasOwnProperty(key)) return obj[key]
}
}
})()
转载自:https://juejin.cn/post/7281840911796977676