沙盒机制的前世今生
介绍为什么油猴需要沙盒环境
本文存在严重性事实漏洞,与实际不符,但有助于理解设计
初代油猴之殇
大概二十年前,早期油猴存在一个重大的安全漏洞,即默认所有的网页都是安全并且可靠的。
当时的执行机制是在网页上创建一个script
元素,插入到页面之中,当脚本执行完毕再删除元素来清理。
简洁的说就是将脚本直接插入到网页当中。
这个机制看似完美,但其实暗藏了三个致命的漏洞
1. 窃取用户脚本代码
当油猴插入脚本的时候会触发DOMNodeInserted事件,所以如果我们使用下列代码
document.addEventListener("DOMNodeInserted",func,true);
这样,当油猴插入脚本的时候会触发网页的恶意代码,并且窃取油猴脚本的代码。
2. 越权使用GM函数
如果是普通网页的函数,一般没有办法跨越网站与其他地方进行通信,但是油猴的GM
函数是极其强大的。
如果我们使用下列代码
window.watch("GM_log",trapGM);
当油猴在插入脚本之前对gm函数初始化,就会被恶意的网页窃取GM
函数的使用权,并且进行使用来与其他地方进行通信。
3. 对本地文件进行访问
油猴可以通过指向本地文件的file://
路径来发起请求,这样就可以读取到用户本地磁盘上的数据,这是一个极其危险的行为
导致一个恶意网站可以窃取用户的磁盘数据并且上传到某个地方
小结
初代油猴由于过于信任网页,导致存在了极其危险的操作,击穿了安全机制,所以作者对其进行了重新设计,提高了安全性。
油猴的脱胎换骨
新生之始
油猴从此痛改前非,不再开始完全相信网页这个渣男,所以我们需要改变之前的思路。
油猴给出的解决方案是提供一个可以执行脚本的安全环境,不再允许网页对脚本进行干扰,以及提升自身权限来进行危险操作。
所以油猴在沙盒里执行用户脚本,并且不再会对网页注入script元素,也不会在全局窗口定义API
函数(这就是为什么none
不允许GM
函数的由来)。
所以网页无法进行拦截和获取脚本的行为,也不存在越权了,脚本也并不再需要修改网页进行初始化。
但是还存在一个问题:
脚本经常会操作网页,使用一些原生函数,例如document.createElement
等等。
这个时候如果网页有恶意行为,对这些行为进行了记录,劫持等等该怎么办?油猴脚本难道坐以待毙么?
美玉无瑕
为了解决这个问题油猴引入了XPCNativeWrappers
机制,由于国内目前没有翻译,我暂且称之为可信任进程通信管道
。
XPCNativeWrapper
机制返回了一个包装过的数据,这个数据是可以信任的,确保不会被网页 进行恶意篡改。
有利就有弊,相应出现的问题就是XPCNativeWrapper
虽然保证了数据不会被篡改,但是也存在许许多多不尽人意的问题。比如:
- 在设置
onclick
回调函数的时候,不可以直接进行赋值; - 在设置自定义属性的时候没有作用
这些都是因为可信任进程通信管道返回的是一个包装后的数据,而不是原来的数据本身,这时候我们只能使用addEventListener
来进行添加onclick
回调函数,使用setAttribute
来设置自定义属性等等。
这是十分繁琐的,但是我们为了安全却又无可奈何。
至此我们讲述了油猴的安全模型,在脚本运行的过程中,这一切都是可信的,网页无法获取脚本源代码,也无法窃取油猴函数的执行权。
我们可以说油猴的安全模型的意思解释出来就是脚本的执行环境必须是可信且安全的。
妥协之策
但是这里还有一些问题,比如我需要使用原网页的函数,这个函数需要传递原网页的数据怎么办?我不想使用setAttribute
,addEventListener
等等,依然想用原来的方法怎么办?
于是油猴提出了一个unsafeWindow
,它是原网页数据的一个引用,我们操纵它就相当于操纵原网页。
但是这里有一个不得不提的问题,就是一旦我们使用了unsafeWindow
,代表我们破坏了油猴的安全模型,unsafeWindow
的内容并不是完全可信的,需要开发者自己对其进行判断以及处理,不能一味的去相信网页。
总结
至此所有的内容已经讲完了,我们最后总结一下
配置 | 特点 |
---|---|
@grant none | 无沙盒环境, 无法调用 GM 函数 |
没有@grant none | 沙盒环境, 用户脚本可以使用 GM 函数原网页无法使用 GM 函数 |
@grant unsafeWindow | 上一行基础下, 允许用户脚本读写原页面内容 |
使用unsafeWindow
所获取的数据,对其进行处理的行为是否是安全并且可靠。
none
是无沙盒环境,因为之前的漏洞总结的经验,现在已经禁止在无沙盒环境使用GM
函数,所以我们脚本在none
的情况下无法调用GM
函数了
没有none
就是沙盒环境,我们开发的脚本可以使用GM
函数,此时已经与网页存在 隔离,网页无法使用GM
函数,但是脚本可以使用GM
函数
当我们使用unsafeWindow
的时候,相当于我们创造了一个原网页的引用可以对其进行数据的读写,但是同时我们也破坏了油猴的安全模型,当然这并不是十分可怕的事情,我们只需要注意一个问题,就是我们使用unsafeWindow
所获取的数据,对其进行处理的行为是否是安全并且可靠的。