javascript 为什么用户脚本中的 window(和 unsafeWindow)与 <script> 标签中的不同?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/10824697/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-26 11:10:14  来源:igfitidea点击:

Why is window (and unsafeWindow) not the same from a userscript as from a <script> tag?

javascriptgreasemonkeyscopeuserscripts

提问by ldiqual

I was facing an issue while developing this small userscript. When I wanted to block every XMLHttpRequestfrom the running website with my script, nothing was happening (at least with Chrome):

我在开发这个小用户脚本时遇到了一个问题。当我想XMLHttpRequest用我的脚本阻止正在运行的网站上的每一个时,什么都没有发生(至少在 Chrome 中):

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();

Same thing when replacing windowby unsafeWindow.

替换windowunsafeWindow.

However, when I used this little trick, everything worked like a charm:

然而,当我使用这个小技巧时,一切都像一个魅力:

// No more call to main(), and:
var script = document.createElement("script");
script.textContent = "(" + main.toString() + ")();";
document.body.appendChild(script);

Every call to xhr.openis replaced by my custom function, no more AJAX.

每次调用xhr.open都被我的自定义函数取代,不再是 AJAX。

So I guess the windowelement is not the same when mainis called from inside the script than when it's called from a <script></script>container. Can someone explain me why ?

所以我猜从脚本内部调用的window元素与main<script></script>容器调用的元素不同。有人可以解释我为什么吗?

回答by Brock Adams

See "Are Chrome user-scripts separated from the global namespace like Greasemonkey scripts?". Both Chrome userscripts/content-scripts and Greasemonkey scripts are isolated from the page's javascript. This is done to help keep you from being hacked, but it also reduces conflicts and unexpected side-effects.

请参阅“Chrome 用户脚本是否像 Greasemonkey 脚本一样与全局命名空间分开?” . Chrome 用户脚本/内容脚本和 Greasemonkey 脚本都与页面的 javascript 隔离。这样做是为了帮助您避免被黑客入侵,但它也减少了冲突和意外的副作用。

However, the methods are different for each browser...

但是,每个浏览器的方法都不同......

Firefox:

火狐:

  1. Runs scripts in an XPCNativeWrapper sandbox, unless @grant noneis in effect (as of GM 1.0).
  2. Wraps the script in an anonymous function by default.
  3. Provides unsafeWindowto access the target page's javascript. But beware that it is possiblefor hostile webmasters to follow unsafeWindowusage back to the script's context and thus gain elevated privileges to pwn you with.
  1. XPCNativeWrapper 沙箱中运行脚本,除非@grant none有效(从 GM 1.0 开始)。
  2. 默认情况下将脚本包装在匿名函数中。
  3. 提供unsafeWindow访问目标页面的javascript。但请注意,敌对的网站管理员可能会跟踪unsafeWindow使用情况回到脚本的上下文,从而获得提升的特权来与您合作。

Chrome:

铬合金:

  1. Runs scripts in an "isolated world".
  2. Wraps the script in an anonymous function.
  3. Strictlyblocks any access to the page's JS by the script and vice-versa.
    Recent versions of Chrome now provide an object named unsafeWindow, for very-limited compatibility, but this object does not provide any access to the target page's JS. It is the same as windowin the script scope (which is not windowin the page scope).
  1. “孤立的世界”中运行脚本。
  2. 将脚本包装在匿名函数中。
  3. 严格阻止脚本对页面 JS 的任何访问,反之亦然。
    最新版本的 Chrome 现在提供了一个名为 的对象,以unsafeWindow实现非常有限的兼容性,但该对象不提供对目标页面的 JS 的任何访问。它与window在脚本范围内(不在window页面范围内)相同。


That said, the version of your script that used unsafeWindowshould work on/in Firefox if implemented correctly. It mightwork using the Tampermonkey extensionon Chrome, but I'm not going to double-check that right now.

也就是说,unsafeWindow如果正确实施,您使用的脚本版本应该在 Firefox 上/在 Firefox 中工作。它可能在 Chrome 上使用Tampermonkey 扩展程序工作,但我现在不打算仔细检查。

When you do that "trick" (var script = document.createElement("script"); ...), you are injectingcode into the target page. This bypasses the sandbox and is the only way on a normal Chrome userscript for a script to interact with the page's JS.

当您执行该“技巧” ( var script = document.createElement("script"); ...) 时,您代码注入目标页面。这绕过了沙箱,并且是普通 Chrome 用户脚本上脚本与页面 JS 交互的唯一方式。

Injection advantages:

注塑优势:

  1. The only way for non-Tampermonkey userscripts to access objects or functions provided by the target page.
  2. Almost always fully compatible between Chrome, Firefox, Opera, etc. (IE is, as always, something else.)
  3. Often easier to debug the whole script; developer tools work normally.
  1. 非 Tampermonkey 用户脚本访问目标页面提供的对象或功能的唯一方法。
  2. 几乎总是在 Chrome、Firefox、Opera 等之间完全兼容(IE 一如既往地是别的东西。)
  3. 通常更容易调试整个脚本;开发人员工具正常工作。

Injection drawbacks:

注射缺点:

  1. The script, at least the injected parts, cannot use the enhanced privileges (especially cross-domain) provided by the GM_functions -- especially GM_xmlhttpRequest().
    Note that currentlyChrome only supports GM_addStyle, GM_xmlhttpRequest, GM_logand GM_openInTab, fully, natively.
    Tampermonkey supports GM_functions almost fully, however.

  2. Can cause side effects or conflicts with the page's JS.

  3. Using external libraries introduces even more conflicts and timing issues. It's nowhere near as easy as @require.
    @require, also runs the external JS from a local copy -- speeding execution and all but eliminating reliance on an external server.

  4. The page can see, use, change, or block the script.

  5. Requires JS to be enabled. Firefox Greasemonkey, especially, can run on a page which has JS blocked. This can be godsend on bloated, crappy, and/or intrusive pages.

  1. 脚本,至少注入的部分,不能使用GM_函数提供的增强权限(尤其是跨域)——尤其是GM_xmlhttpRequest().
    请注意,目前Chrome 仅支持GM_addStyleGM_xmlhttpRequestGM_logGM_openInTab,完全本机。然而,
    TampermonkeyGM_几乎完全支持函数。

  2. 可能会导致副作用或与页面的 JS 发生冲突。

  3. 使用外部库会引入更多冲突和时序问题。它远没有那么容易@require
    @require,还从本地副本运行外部 JS - 加快执行速度,几乎消除对外部服务器的依赖。

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

  5. 需要启用 JS。尤其是 Firefox Greasemonkey,它可以在 JS 被阻止的页面上运行。这在臃肿、蹩脚和/或侵入性页面上可能是天赐之物。