Why is window (and unsafeWindow) not the same from a userscript as from a <script> tag?
在开发这个小的用户脚本时,我遇到了一个问题。当我想用我的脚本阻止运行中的网站上的每一个XMLHttpRequest时,什么都没有发生(至少用chrome):
1 2 3 4 5 6 7
| function main() {
// Override XHR.open with a custom function
window.XMLHttpRequest.prototype.open = function() {
// Nothing... so it's supposed to block every xhr.open() call
}
}
main(); |
用unsafeWindow替换window时也是一样。
然而,当我使用这个小把戏时,一切都像是一种魅力:
1 2 3 4
| // No more call to main(), and:
var script = document.createElement("script");
script.textContent ="(" + main.toString() +")();";
document.body.appendChild(script); |
对xhr.open的每个调用都被我的自定义函数取代,不再使用ajax。
所以我猜当从脚本内部调用main时,window元素与从容器调用时不同。有人能解释一下为什么吗?
请参见"Chrome用户脚本是否与全局命名空间分离,如GreaseMonkey脚本?".chrome用户脚本/内容脚本和greasemonkey脚本都与页面的javascript分离。这样做有助于防止被黑客攻击,但也减少了冲突和意外的副作用。
但是,每个浏览器的方法不同…
Firefox:
在xpcnativewrapper沙盒中运行脚本,除非@grant none生效(从gm 1.0开始)。
默认情况下,将脚本包装在匿名函数中。
提供unsafeWindow以访问目标页面的javascript。但是要注意,敌对的网站管理员有可能遵循unsafeWindow的用法返回到脚本的上下文,从而获得提升的特权来给您pwn。
铬:
在"孤立的世界"中运行脚本。
在匿名函数中包装脚本。
严格阻止脚本访问页面的JS,反之亦然。Chrome的最新版本现在提供了一个名为unsafeWindow的对象,兼容性非常有限,但是这个对象不提供对目标页面的JS的任何访问。它与脚本范围内的window相同(页面范围内不是window)。
也就是说,如果正确实现,那么使用unsafeWindow的脚本版本应该在Firefox上/中工作。在Chrome上使用Tampermonkey扩展可能有效,但我现在不想再检查一遍。
当你做那个"技巧"(var script = document.createElement("script"); ...时,你是在向目标页面注入代码。这将绕过沙盒,并且是普通chrome用户脚本上脚本与页面的JS交互的唯一方法。
注射优点:
非篡改用户脚本访问目标页面提供的对象或函数的唯一方法。
几乎总是完全兼容chrome、firefox、opera等(也就是说,像往常一样,是其他东西)。
通常更容易调试整个脚本;开发人员工具工作正常。
注射缺陷:
脚本(至少是注入部分)不能使用由GM_函数(尤其是GM_xmlhttpRequest())提供的增强特权(特别是跨域)。请注意,目前Chrome只支持GM_addStyle、GM_xmlhttpRequest、GM_log和GM_openInTab,完全本地支持。然而,tampermonkey几乎完全支持GM_功能。
可能导致副作用或与页面的JS冲突。
使用外部库会带来更多的冲突和时间问题。它远不如@require那么简单。@require还从本地副本运行外部JS——加快了执行速度,几乎消除了对外部服务器的依赖。
页面可以查看、使用、更改或阻止脚本。
需要启用JS。尤其是火狐Greasemonkey,可以在JS阻塞的页面上运行。这可能是天赐之物,在膨胀,蹩脚,和/或侵入性的网页。