以不可检测/可逆的方式更改 Window.prototype.open
我正在研究如何通过扩展来扩展 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
您可以尝试使用
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 likeObject.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.最后我不得不放弃使用 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 originalwindow.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 callwindow.stop()
(stops all network activities before any network requests are sent) andwindow.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:about:blank
first before changing to their actual destination. For same-origin pop-ups the latter won't send a newcontent-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.
Web 浏览器有意阻止这种行为,这是为了维护 Web 的安全性,例如,当您使用 iFrame 时,您不希望 iFrame 弄乱或破解您的页面。
但是,为什么不为窗口对象创建一个包装器并通过包装器在本地覆盖窗口,而不是操作窗口对象属性呢?
示例:
顺便说一句,这仅影响 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:
BTW this affects only the body inside fakeScope() function, and cannot be applied globally.
今天早上我突然想到:你可以使用
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 ;)