likes
comments
collection
share

闭包代码的提权漏洞

作者站长头像
站长
· 阅读数 11

在开发中,我们经常会碰到使用闭包的场景,我们使用闭包的目的,是想要对一些数据进行保护来避免外界修改,有这么一个闭包函数,我们来看看它存在的漏洞

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]
        }
    }
})()