如何查看哪个选项卡打开(弹出)窗口?

时间:2017-09-25 13:59:52

标签: javascript google-chrome-extension

问题

我已经有这个问题好几个月,但这个概念很简单:我想阻止一些恶意网站™以编程方式打开标签或弹出窗口。

使用chrome.tabs API,我可以在创建新标签时使用onCreated进行收听,然后我可以轻松检查哪个(即哪个标签页)打开了访问{{1传递给回调函数的Tab对象的属性。

现在,我想在创建新窗口时做同样的事情:我想知道哪个标签打开了窗口(如果有的话,因为它可能已被打开了用户也是),检查其URL以查看它是否为恶意网站™,并采取相应措施(即阻止弹出窗口)。我尝试以完全相同的方式执行此操作:在新窗口中请求选项卡数组并检查其openerTabId属性,但遗憾的是,此属性未定义!我搜索了the documentation和谷歌搜索了几个小时,但遗憾的是,看起来没有简单的方法来检查是谁打开了一个窗口。

非常笨拙的解决方案

如上所述,我能够做到甚至远远接近我真正想要的东西的唯一方法如下:

  1. 每次创建新的窗口 时,其ID都会添加到名为openerTabId的数组中。
  2. 每次标签 更新(注意:已更新,未创建)时,会在其中注入一个脚本以检查其windowWatchlist,其中 应包含打开标签的网站的网址:如果引荐来源网址包含我要阻止弹出窗口的恶意网站的地址,则该窗口将关闭并从document.referrer中删除
  3. 每次窗口 关闭时,如果其ID在windowWatchlist中,则会从中删除。
  4. 这是代码(在我的windowWatchlist脚本中运行):

    background.js

    现在,你可能想知道:为什么你只需要检查一个推荐人,你为什么需要所有这些混乱?你不能只是在打开窗口时检查窗口中包含的标签并检查它们引用者直接在// Called on chrome.windows.onCreated function watchPopupWindow(window) { windowWatchlist.push(window.id); console.log('Added window #' + window.id + ' to watchlist.'); } // Called on chrome.windows.onRemoved function unwatchPopupWindow(windowID) { var index = windowWatchlist.indexOf(windowID); // If the windowID is in the watchlist: if (index != -1) { // Remove it: windowWatchlist.splice(index, 1); console.log('Removed window #' + windowID + ' from watchlist.'); } } // Called on chrome.tabs.onUpdated function blockPopupWindow(tabID, info, tab) { // If this tab is in a window which is in the watchlist: if (windowWatchlist.indexOf(tab.windowId) != -1 && info.url && info.url != 'about:blank') { // Check the referrer of this tab: chrome.tabs.executeScript(tabID, {code: 'document.referrer;'}, function(ref) { // If the referrer is the malicious site to block: if (ref && ref[0] && ref[0].indexOf("http://MALICIOUS-SITE.XXX") != -1) { // Close the popup window: chrome.windows.remove(tab.windowId, function() { console.log('Blocked popup window #' + tab.windowId + '.'); if (chrome.runtime.lastError) console.error(chrome.runtime.lastError.message); });; } }); } } var windowWatchlist = []; chrome.windows.onCreated.addListener(watchPopupWindow, {windowTypes: ['popup']}); chrome.windows.onRemoved.addListener(unwatchPopupWindow, {windowTypes: ['popup']}); chrome.tabs.onUpdated.addListener(blockPopupWindow); 的回调中?这是一个聪明的问题,答案很简单:问题是我无法在创建选项卡时检查它们的引用者,因为它们几乎总是需要一些时间来加载,而引用者不是加载,直到页面开始在选项卡内加载。因此,我需要检查选项卡何时更新,查看其窗口是否在我的监视列表中,然后检查其引用者。这就是为什么需要chrome.window.onCreated的原因,因为只要标签更改状态(例如chrome.tabs.onUpdatedtab.status更改为"loading"),它就会触发其侦听器。

    为什么此解决方案不起作用

    我称这个解决方案“笨拙”的原因以及它之所以无法正常工作的原因应该已经让任何具有JavaScript和网络开发经验的人都清楚了: "complete"不可靠在所有,并且经常document.referrer或(在多重重定向的情况下)不是正确的。这使得我的脚本在大约90%的时间内失败,因为它无法确定弹出窗口是否被恶意网站™打开。

    此外,恶意网站™通常会打开包含网址undefined或根本没有网址的弹出窗口,只有在加载时,才会向其中注入数据,这使得它们基本上无法检测到,即使使用{{1}在这种情况下,它不会触发任何监听器。

    我可以决定使用网址about:blankchrome.tabs.onUpdated阻止任何弹出窗口,这就是我现在正在做的事情,但这是一个非常糟糕的妥协,因为我最终关闭弹出窗口由任何使用此方法的网站打开,而不仅仅是我想阻止的恶意网站。

    总结

    我的问题很简单,但我不知道它的解决方案:有没有人知道任何其他更可靠的方法,可以用来检测谁打开了一个新窗口?没有任何事情发生在我脑海中,也许使用chrome.webRequest API可能有什么事情可做?我真的不知道。几个月来,我一直在接受这样一个事实:一个简单的解决方案是不可能的,并且无助地等待更新或其他什么,但我从未真正想过在这里问,因为问题看起来高于普通Chrome扩展程序员的能力,但希望我错了。

    更新:在网站内部注入脚本并将about:blank函数替换为其他内容的解决方案是不可行的:如果加载了undefined而没有{ {1}}属性,但在window.open属性中已经写好的DOM,即使使用<iframe>调用src,Chrome也不会在其中执行内容脚本,即使内容脚本在扩展的清单中声明。

2 个答案:

答案 0 :(得分:2)

我遇到了同样的问题,发现webNavigation.onCreatedNavigationTarget事件在打开新窗口时产生了源标签/框架ID。

从这篇文章中找到解决方案:Is it possible to determine a tab's opener within a Google Chrome extension?

答案 1 :(得分:1)

由于你已经在进行代码注入,这就是我要做的。

注入代码以覆盖window.open并将其window.postMessage置于子窗口,告诉他们是谁打开了它们。还需要注入代码来聆听window.addEventListener('message', messageHandler)的效果,这将决定它们是否window.close()

第二个虽然我想我会覆盖window.open,如果你不想让一个赠送网站打开窗户,你甚至不打开子窗口。