关于javascript:为什么window(和unsafeWindow)与用户脚本和< script>不一样?

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_addStyleGM_xmlhttpRequestGM_logGM_openInTab,完全本地支持。然而,tampermonkey几乎完全支持GM_功能。

  • 可能导致副作用或与页面的JS冲突。

  • 使用外部库会带来更多的冲突和时间问题。它远不如@require那么简单。@require还从本地副本运行外部JS——加快了执行速度,几乎消除了对外部服务器的依赖。

  • 页面可以查看、使用、更改或阻止脚本。

  • 需要启用JS。尤其是火狐Greasemonkey,可以在JS阻塞的页面上运行。这可能是天赐之物,在膨胀,蹩脚,和/或侵入性的网页。