在解析v-if和v-for等指令时我们会看到通过evaluate执行指令值中的JavaScript表达式,而且能够读取当前作用域上的属性。而evaluate的实现如下:
const evalCache: Record<string, Function> = Object.create(null)
export const evaluate = (scope: any, exp: string, el?: Node) =>
execute(scope, `return(${exp})`, el)
export const execute = (scope: any, exp: string, el?: Node) => {
const fn = evalCache[exp] || (evalCache[exp] = toFunction(exp))
try {
return fn(scope, el)
} catch (e) {
if (import.meta.env.DEV) {
console.warn(`Error when evaluating expression "${exp}":`)
}
console.error(e)
}
}
const toFunction = (exp: string): Function => {
try {
return new Function(`$data`, `$el`, `with($data){${exp}}`)
} catch (e) {
console.error(`${(e as Error).message} in expression: ${exp}`)
return () => {}
}
}
简化为如下
export const evaluate = (scope: any, exp: string, el?: Node) => {
return (new Function(`$data`, `$el`, `with($data){return(${exp})}`))(scope, el)
}
而这里就是通过with+new Function构建一个简单的沙箱,为v-if和v-for指令提供一个可控的JavaScript表达式的执行环境。
什么是沙箱
沙箱(Sandbox)作为一种安全机制,用于提供一个独立的可控的执行环境供未经测试或不受信任的程序运行,并且程序运行不会影响污染外部程序的执行环境(如篡改/劫持window对象及其属性),也不会影响外部程序的运行。
与此同时,沙箱和外部程序可以通过预期的方式进行通信。
更细化的功能就是:
- 拥有独立的全局作用域和全局对象(
window) - 沙箱提供启动、暂停、恢复和停机功能
- 多台沙箱支持并行运行
- 沙箱和主环境、沙箱和沙箱之间可实现安全通信
原生沙箱-iframe
iframe拥有独立的browser context,不单单提供独立的JavaScript执行环境,甚至还拥有独立的HTML和CSS命名空间。
通过将iframe的src设置为about:blank即保证同源且不会发生资源加载,那么就可以通过iframe.contentWindow获取与主环境独立的window对象作为沙箱的全局对象,并通过with将全局对象转换为全局作用域。
而iframe的缺点:
- 若我们只需要一个独立的JavaScript执行环境,那么其它特性则不仅仅是累赘,还会带来不必要的性能开销。而且
iframe会导致主视窗的onload事件延迟执行; - 内部程序可以访问浏览器所有API,我们无法控制白名单。(这个可以通过Proxy处理)

本文深入剖析 Petite-Vue 中的沙箱模型,讲解了什么是沙箱、原生沙箱的优缺点、如何防止绑定解析逃逸以及实现一个基本安全的沙箱。重点探讨了如何通过 Proxy 控制作用域链,防止沙箱逃逸,并提到了沙箱的其他功能实现。
最低0.47元/天 解锁文章
2533

被折叠的 条评论
为什么被折叠?



