跳到主要内容

沙盒机制的前世今生

介绍为什么油猴需要沙盒环境

危险

本文存在严重性事实漏洞,与实际不符,但有助于理解设计

初代油猴之殇

大概二十年前,早期油猴存在一个重大的安全漏洞,即默认所有的网页都是安全并且可靠的。

当时的执行机制是在网页上创建一个script元素,插入到页面之中,当脚本执行完毕再删除元素来清理。

简洁的说就是将脚本直接插入到网页当中。

这个机制看似完美,但其实暗藏了三个致命的漏洞

1. 窃取用户脚本代码

当油猴插入脚本的时候会触发DOMNodeInserted事件,所以如果我们使用下列代码

警告

目前MutationEvent已被废除,保留该段仅供学习思路

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来设置自定义属性等等。

这是十分繁琐的,但是我们为了安全却又无可奈何。

至此我们讲述了油猴的安全模型,在脚本运行的过程中,这一切都是可信的,网页无法获取脚本源代码,也无法窃取油猴函数的执行权。

我们可以说油猴的安全模型的意思解释出来就是脚本的执行环境必须是可信且安全的。

妥协之策

但是这里还有一些问题,比如我需要使用原网页的函数,这个函数需要传递原网页的数据怎么办?我不想使用setAttributeaddEventListener等等,依然想用原来的方法怎么办?

于是油猴提出了一个unsafeWindow,它是原网页数据的一个引用,我们操纵它就相当于操纵原网页。

但是这里有一个不得不提的问题,就是一旦我们使用了unsafeWindow,代表我们破坏了油猴的安全模型,unsafeWindow的内容并不是完全可信的,需要开发者自己对其进行判断以及处理,不能一味的去相信网页。

总结

至此所有的内容已经讲完了,我们最后总结一下

配置特点
@grant none无沙盒环境,
无法调用GM函数
没有@grant none配置沙盒环境,
用户脚本可以使用GM函数
原网页无法使用GM函数
@grant unsafeWindow上一行基础下,
允许用户脚本读写原页面内容
危险

使用unsafeWindow所获取的数据,对其进行处理的行为是否是安全并且可靠。


none是无沙盒环境,因为之前的漏洞总结的经验,现在已经禁止在无沙盒环境使用GM函数,所以我们脚本在none的情况下无法调用GM函数了

没有none就是沙盒环境,我们开发的脚本可以使用GM函数,此时已经与网页存在隔离,网页无法使用GM函数,但是脚本可以使用GM函数

当我们使用unsafeWindow的时候,相当于我们创造了一个原网页的引用可以对其进行数据的读写,但是同时我们也破坏了油猴的安全模型,当然这并不是十分可怕的事情,我们只需要注意一个问题,就是我们使用unsafeWindow所获取的数据,对其进行处理的行为是否是安全并且可靠的。