JavaScript proxy浅析-防止篡改

156 阅读1分钟

简介

JavaScript的proxy是一种对象,可以用来创建一个原始对象的代理,从而实现对基本操作的拦截和自定义,如属性查找、赋值、枚举、函数调用等

例子

image.png

let person = {name: "tim", age: 3}

let pproxy = new Proxy(person, {
    get: function (target, prop) {
        //target有prop这个属性就返回它的值,否则返回0
        return prop in target ? target[prop] : 0;
    }

})
console.log(pproxy.name);
console.log(pproxy.email);

output

tim
0  

pproxy 就是图中的proxyUser, 对user的所有操作又要经过proxyUser,例子中对person 的操作都要交经过pproxy(但是我的person在外面啊,可以篡改啊! 伏笔),

为什么

let proxy = new Proxy(target,handle)

实例化一个Proxy对象,这个对象的target是我们要代理的对象, 也可以说我们要保护的对象,handle(捕获器)用来拦截和修改目标对象的操作的函数.

let person = {name: "tim", age: 3}

let pproxy = new Proxy(person, {
    get: function (target, prop) {
        return prop in target ? target[prop] : 0;
    }, // 捕获器之间加 ,
    set(target, prop, value) {
        if (prop === "age") {
            if (!(age >= 0 && age <= 100)) {
                return false
            }
            target[age] = value
            console.log(target[prop])
            return true //set 捕获器需要return bool,判断是否赋值成功
        }
    }
})
person.age = 34  // 未经过代理,篡改person
console.log(person.age);
console.log(pproxy.age);

output:

34
34

由于person在外面, 可以直接篡改,故将person写到proxy里的target

let pproxy = new Proxy({name: "tim", age: 3}, {})

现在pproxy代理的是一个匿名的对象,外部无法访问

篡改

let person = {age: 19}

function proxy({data}) {
    let value = data.age //记下n 的值
    //此时person的age已经被删除了, 访问age通过getter setter
    Object.defineProperty(data, 'age', {
        get() {
            return value
        },
        set(newValue) {
            if (newValue > 10) {
                value = newValue;
                return true
            } else
                return 0
        },
    })
    //代理对象
    let obj = {}
    Object.defineProperty(obj, 'age', {
        get() {
            return data.age
        },
        set(newValue) {
            data.age = newValue
        }
    })
    return obj
}

let obj = proxy({data: person})
person.age = 9
console.log(person.age)
person.age = -99
console.log(person.age)
person.age = 99
console.log(person.age)
console.log("---------------")
obj.age = -99
console.log(obj.age)
obj.age = 99999
console.log(obj.age)

output:

19 //直接访问person 修改数据失败,不符合setter
19 //直接访问person 修改数据失败,不符合setter            
99             
---------------
99 // 代理的值不符合setter 被拦截了,修改失败            
99999     

此时不可以直接通过person.age直接修改值, 我们将age 提取出来,此时添加defineProperty, 此时的age只能通过里面的setter 和getter 访问