以不可检测/可逆的方式更改 Window.prototype.open

发布于 2024-11-19 05:13:32 字数 950 浏览 4 评论 0原文

我正在研究如何通过扩展来扩展 Firefox 弹出窗口阻止功能。一种选择是用包装函数替换网页中的 window.open() (或者更确切地说 Window.prototype.open())。一个重要的要求是网页无法检测或恢复这种操作。例如,如果我只是这样做:

Window.prototype.open = wrapper;

网页可以通过执行以下操作轻松恢复更改:

delete Window.prototype.open;

相反,我可以使用 Object.defineProperty() 设置高级属性标志:

Object.defineProperty(Window.prototype, "open", {value: wrapper, configurable: false});

网页无法再恢复此更改,但仍然可以检测到它:delete Window.prototype.open 通常会更改 Window.prototype.open 的值(看起来是同一函数的不同实例),这里 delete 不会根本没有任何影响。另外, Window.prototype.open = "test";delete Window.prototype.open; 将产生不一致的结果(不同的结果取决于是否指定了 writable: false 标志财产)。

我还能做些什么来模拟原始属性的行为(除了使用二进制 XPCOM 组件之外,它本身有太多问题)?

I am looking into ways to extend Firefox pop-up blocking from an extension. One option is replacing window.open() (or rather Window.prototype.open()) in the webpage by a wrapper function. An important requirement is that this manipulation cannot be detected or reverted by the webpage. For example, if I simply do this:

Window.prototype.open = wrapper;

The webpage can easily revert the change by doing:

delete Window.prototype.open;

Instead I can use Object.defineProperty() to set advanced property flags:

Object.defineProperty(Window.prototype, "open", {value: wrapper, configurable: false});

The webpage can no longer revert this change but it can still detect it: delete Window.prototype.open normally changes the value of Window.prototype.open (different instance of the same function it seems), here delete won't have any effect at all. Also, Window.prototype.open = "test";delete Window.prototype.open; will produce inconsistent results (different ones depending on whether writable: false flag is specified for the property).

Is there anything else that I can do to emulate the behavior of the original property (short of using binary XPCOM components which has way too many issues of its own)?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

小矜持 2024-11-26 05:13:32

您可以尝试使用 nsIWindowWatcher注册您自己的窗口创建器的接口(nsIWindowCreator)。这样您就可以控制是否打开新窗口,而不会影响窗口对象本身(从而对网站保持不可见)。

我不确定在无法检测到的情况下无法更改 window.open() 的实现是否是一个错误。也许它只是不被认为是像Object.defineProperty这样的方法的重要要求。但也许值得提交一个错误,看看其他人对未来将其作为一个选项的想法。毕竟,广告拦截是一个主要用例。

You might try using the nsIWindowWatcher interface to register your own window creator (nsIWindowCreator). That way you can control whether a new window is opened without affecting the window object itself (and thus remaining invisible to web sites).

I'm not sure whether the inability to change the implementation of window.open() without this being detectable is a bug. Perhaps it's just not considered an important requirement for methods like Object.defineProperty. But it might be worth filing a bug to see what others think about making this an option in the future. After all, ad blocking is a major use case.

高跟鞋的旋律 2024-11-26 05:13:32

最后我不得不放弃使用 JavaScript 代理来完成这项工作。尽管经过一些努力,我可以为 window.open() 创建一个包装器,其行为与原始包装器完全相同(需要考虑 bug 650299),似乎没有合适的方法来替换原来的 window.open() 函数。更改后的属性的行为总是与原始属性不同,这太糟糕了。

因此,我决定采用不同的方法作为弹出窗口阻止解决方案:监听 content -document-global-created 通知 并查看主题(新窗口)及其开场白。具有非空开启器的窗口是某种弹出窗口。人们可以查看 URL 并决定是否应阻止弹出窗口。要阻止其中一个,请调用 window.stop()(在发送任何网络请求之前停止所有网络活动)和 window.close()。后者必须异步(有延迟)调用,因为否则在窗口初始化继续时会导致崩溃。关于此方法的一些注意事项:

  • 对于在新窗口中打开的弹出窗口,该窗口仍会显示,但会立即消失。这似乎是不可避免的。
  • 对于网页来说,它的弹出窗口看起来像是打开了,但立即关闭了 - 这不是内置弹出窗口阻止程序的工作原理,更像是外部弹出窗口阻止应用程序。
  • 新窗口总是先加载about:blank,然后再更改为实际目的地。对于同源弹出窗口,后者不会发送新的 content-document-global-created 通知,这是不幸的。

总而言之:不完美但可用。而且它非常简单,远不及 JavaScript 代理所需的代码量。

In the end I had to give up on using JavaScript proxies for the job. Even though with some effort I can create a wrapper for window.open() that behaves exactly like the original (bug 650299 needs to be considered), there doesn't seem to be a proper way to replace the original window.open() function. The changed property will always behave differently from the original one, too bad.

So I decided to go with a different approach as a pop-up blocking solution: listen for content-document-global-created notification and have a look at the subject (the new window) as well as its opener. Windows with a non-null opener are pop-up windows of some kind. One can look at the URLs and decide whether the pop-up should be blocked. To block one would call window.stop() (stops all network activities before any network requests are sent) and window.close(). The latter has to be called asynchronously (with a delay) because it will cause a crash otherwise as the initialization of the window continues. Some notes on this approach:

  • For pop-ups opening in a new window the window will still show up but disappear immediately. This seems to be unavoidable.
  • For the web page it looks like its pop-up window opened but was closed immediately - this isn't how the built-in pop-up blocker works, more like an external pop-up blocking application.
  • New windows always load about:blank first before changing to their actual destination. For same-origin pop-ups the latter won't send a new content-document-global-created notification which is unfortunate.

All in all: not perfect but usable. And it is very simple, nowhere near the amount of code required for JavaScript proxies.

迷离° 2024-11-26 05:13:32

Web 浏览器有意阻止这种行为,这是为了维护 Web 的安全性,例如,当您使用 iFrame 时,您不希望 iFrame 弄乱或破解您的页面。

但是,为什么不为窗口对象创建一个包装器并通过包装器在本地覆盖窗口,而不是操作窗口对象属性呢?

示例:

// Copy window object to wraper
var wrapper = {};
for(prop in window) {
  wrapper[prop] = window[prop];
}

wrapper.open = function yourNewOpenFunction() {
  /// do your custom code here
}

(function fakeScope(window){
    window.open(); // this is wrapper.open
}(wrapper));

顺便说一句,这仅影响 fakeScope() 函数内部的主体,并且不能全局应用。

Web browsers intentionally prevent this behavior, it's for maintaing the security of web e.g. when you use iFrame you don't want that iFrame to mess up or hack your page.

But instead of manipulating the window object properties why not to create a wrapper for the window object and override window by the wrapper locally?

Example:

// Copy window object to wraper
var wrapper = {};
for(prop in window) {
  wrapper[prop] = window[prop];
}

wrapper.open = function yourNewOpenFunction() {
  /// do your custom code here
}

(function fakeScope(window){
    window.open(); // this is wrapper.open
}(wrapper));

BTW this affects only the body inside fakeScope() function, and cannot be applied globally.

偏爱你一生 2024-11-26 05:13:32

今天早上我突然想到:你可以使用 Object.freeze(Window.prototype);
测试表明,受此保护的方法无法被删除,但它们很容易检测


旧答案:

ES:Harmony 代理 ?
http://brendaneich.com/2010/11/proxy-inception/

当然,它们不稳定,但它们可以在 Firefox 4+ 中工作,而你不是那个害怕困难的人;)

it striked me this morning: you can use Object.freeze(Window.prototype); !
test have shown, that methods protected with this cannon be deleted, but they can be easily detected.


old answer:

What about ES:Harmony Proxies ?
http://brendaneich.com/2010/11/proxy-inception/

Of course, they are unstable, but they are working in Firefox 4+, and you are not the man, who is afraid of difficulties ;)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文