2011-09-21 62 views
9

我正在处理一些需要作为页面运行的代码,并且如果它以Chrome Extension的形式运行,我希望能够执行其他操作。什么我使用的是:检测代码是否作为Chrome扩展程序运行

<script> 
if (chrome && chrome.extension) { 
    // extension stuff 
} 
</script> 

这似乎是一个很好的​​detection。使用用户代理字符串会引起我的麻烦,因为无论上下文(网页还是扩展名)都是相同的。

问题:还有其他更可靠的技术用于检测一段代码是否在Chrome扩展中运行?

更新:我想知道是否有什么我可以放入我的manifest.json文件中,然后我可以回读。请注意,我正在处理的扩展并不是一直运行的持久性事物,它是一个运行在单个窗口或浏览器选项卡中的内容应用程序,无需与其他窗口或选项卡或其他任何内容交互。

+1

You co尽管检查扩展状态并不是它的预期目的:http://code.google.com/chrome/extensions/i18n.html –

回答

18

很多复杂的答案她E,而你可以很容易地检测出是否你在一个浏览器扩展程序通过检查的chrome.runtime.id存在和非空运行:

if (window.chrome && chrome.runtime && chrome.runtime.id) { 
    // Code running in a Chrome extension (content script, background page, etc.) 
} 
+1

优秀点。 'chrome.runtime'作为2012年9月25日发布的Chrome 22(https://developer.chrome.com/extensions/runtime#property-id)的一部分发布(http://googlechromereleases.blogspot.com/2012/09 /stable-channel-update_25.html)...在提问和接受答案发布一年后。我正在更新接受的答案。 感谢掘尸! – artlung

+0

在这两种情况下,条件都是真的,我们可以从扩展弹出式窗口或浏览器页面视图中进行检查。 –

4

务实,这是一个很好的方法。理论上(不确定这是否相关,例如可能会提供漏洞),它可能很容易被欺骗。我想这取决于你的背景是多么相关。

这里的一个略强的想法:

if (chrome && 
    chrome.windows && 
    chrome.windows.get && 
    typeof chrome.windows.get === 'function' && 
    chrome.windows.get.toString() === 'function get() { [native code] }') 

的想法是你的一样,虽然它的稍强,因为AFAIK具有对象是一个函数,并具有它的toString()值具有值是不可能的,因为它是无效的语法,因此即使试图欺骗该值也不会工作,除非您更改了本机代码(这需要完全不同级别的黑客)。

不要手边记住,如果检查这样的事情需要权限或不,但这个想法是明确的,我希望。

UPDATE

我只是意识到了“原生代码”语法的想法可以通过混淆现有的功能所迷惑。例如。

var FakeFn = Object.create; 
FakeFn.toString(); // "function create() { [native code] }" 

但是,可以通过仔细选择我们使用的函数来处理,因为名称出现在字符串中。 get可能太常见了,但如果我们使用一个模糊的函数名称(如的captureVisibleTab)仅在chrome扩展中实现,它仍然是一个非常便携的解决方案,因为与其他本地用户可能欺骗代码的基本检查不同代码,事先知道浏览器不会使用这个名称实现任何原生函数,所以它在所有浏览器和所有用户代码中都是安全的。

UPDATE

由于@Mathew指出,这种想法是foolable(虽然看似只有恶意)。我认为我可以通过比较Function.prototype.toString来修补问题,但认为即使是这样也可以通过假冒原始toString方法并创建一个新方法来欺骗某些函数返回假字符串,并为其他字符返回原始字符串。总之,我的想法比原来稍微强一点,因为它几乎可以排除所有意外碰撞的机会(稍微超过OP的想法),但当然不能防御恶意攻击,正如我第一次想到的那样有可能。

+0

有趣,并按预期工作,但我不相信它比我的便携更便携。我想知道是否有什么我可以放入我的'manifest.json'文件中,然后我可以以某种方式读回。感谢您的支持。 – artlung

+1

@artlung,任何此类方法都不如我的便携式,让我解释一下:整个扩展API(AFAIK,我承认API不是很专业)是基于javascript的。所以所有的调用都将符合JS标准,并且会采用常规的'obj.ref.fn()'形式,这个形式根据定义可以被愚弄。我的方法更便携的原因是因为它不能被愚弄。除非您篡改浏览器本身,否则您无法创建一个能够通过这些条件的对象,但是我可以在任何浏览器中轻松创建'window.chrome = {extension:true}',您的代码会认为它是一个扩展名。 – davin

+0

你说得很好。我认为我的目的不是严格执行非欺骗,而仅仅是区分简单使用Chrome(以及许多变体)和作为extenson的一部分加载的代码。非常感谢你仔细考虑这个! – artlung

2

我知道这是旧的,但只是想我会提供一个替代方案。您可以将其他JavaScript文件添加到Chrome扩展,因此它包含两个.js文件。 manifest.json的将有:

"js": ["additionalscript.js", "yourscript.js"] 

的additionalscript.js可以简单地声明一个变量var isextension = true。 yourscript.js可以检查typeof isextension != 'undefined'

但也许更有趣的例子,它可以宣布

var adminpassword='letmein' 

现在yourscript.js只能访问在扩展运行时ADMINPASSWORD。

+0

我认为你的意思是“脚本”而不是“js”。你总是希望以'typeof isextension!='undefined''来执行测试,否则当additionalscript.js没有被执行时你会得到一个JavaScript异常。您还应该注意到这是在清单的“背景”部分。 –

+0

谢谢@DanMcGrath - 我有一个“content_scripts”部分的manifest.json有一个“js”条目:“content_scripts”:[ { “matches”:[“*://*.google.com/* “], ”js“:[”One.js“,”Two.js“] } ]。并重点检查undefined –

1

我注意到,在铬,铬对象,即全局窗口的属性(当然,如果插件都可能受到影响的机器上,你就不会在脚本文件中嵌入密码)对象,无法删除。如果是用户定义的属性删除操作成功。所以,你可以用这种方式进行测试:

var isRunningInExtension = (!(delete window.chrome) && chrome.extension) ? 
          true : false; 

UPDATE: 线之上并没有真正保证代码在浏览器扩展程序运行。每个人都可以使用“扩展”属性创建一个名为'chrome'的对象,然后冻结/密封该对象 - 这样做足以通过检查并且导致代码在Chrome扩展中运行的结果不正确。

确保您在扩展中运行代码,您必须在运行任何JavaScript之前测试全局chrome对象 - 这样才能保证在测试之前不会创建伪造的chrome对象。

一个可能的解决方案是使用iframe - 在我的示例中,我使用iframe的沙箱属性来指示iframe不执行任何脚本(即使脚本包含脚本标记) - 这样我就可以确保脚本不会能够修改全局的window.chrome对象。

(function() { 
    var isChromeExtension = (function() { 
    var contentWindow, 
     iframe = document.createElement("iframe"), 
     isChromeExtension; 
    // test for sandbox support. It is supported in most recent version of Chrome 
    if ("sandbox" in iframe) { 
     try { 
     iframe.sandbox = "allow-same-origin"; 
     iframe.src=location.href; 
     iframe.style="display: none"; 
     document.body.appendChild(iframe); 
     contentWindow = iframe.contentWindow; 
     isChromeExtension = !!(contentWindow.chrome && contentWindow.chrome.extension); 
     document.body.removeChild(iframe); 
     } catch(e) {} 
    } 
    return isChromeExtension; 
    }()); 
}()); 

结果可能是:

  • 真实的 - 如果代码是Chrome浏览器的扩展内部运行
  • 假 - 如果代码不镀铬的扩展内部运行
  • 不确定的 - 如果浏览器不支持沙箱的iframe或在测试过程中发生一些错误
+0

我不清楚你对'删除'工作的理解如你所说。我也可以创建一个对象,比如'window.g = {x:1}',然后运行delete并在尝试删除时获得类似的false结果。 ......也许这个工作的一个更完整的例子是需要的。 – artlung

+0

你的新方法不是非常高效,也不是非常简单。如果环境真的是恶意的,那么任何对象,包括'document'都可能被欺骗。没有办法为此辩护,所以你应该选择最可读和直接的方法。 –

+0

确实不是很高效 - 它将整个页面/样式/脚本加载到iframe中,但没有一个脚本会被执行(内联或包含在脚本标记中) - 这是沙盒的作用 - 所以没有办法客户端改变全局对象,甚至模仿文档对象。 请记住,铬对象不能被删除,但每个人都可以覆盖它 - 所以,我可以做到以下几点: 'window.chrome = {runtime:{id:{}}};'和你的建议答案会说我的代码在扩展中运行,但事实并非如此。 – ttsvetkov

1

Chrome不提供任何直接的API来检查应用程序的运行状态是它在扩展弹出窗口或铬页面视图中运行。然而,一个间接技巧可以工作的是,我们可以匹配等于或小于CSS中指定的扩展主体分辨率(在这种情况下,扩展弹出框将打开)或大于此值(在这种情况下,网页视图将是打开)。

1

我需要类似的东西。

但我并不需要关心试图欺骗代码的网站。

const SCRIPT_TYPE = (() => { 
    if (chrome && chrome.extension && chrome.extension.getBackgroundPage && chrome.extension.getBackgroundPage() === window) { 
     return 'BACKGROUND'; 
    } else if (chrome && chrome.extension && chrome.extension.getBackgroundPage && chrome.extension.getBackgroundPage() !== window) { 
     return 'POPUP'; 
    } else if (!chrome || !chrome.runtime || !chrome.runtime.onMessage) { 
     return 'WEB'; 
    } else { 
     return 'CONTENT'; 
    } 
})(); 

上述应检测的4个场景

  • JavaScript在后台页面运行
  • JavaScript是运行在一个弹出页面
  • JavaScript是在上下文中的脚本运行
  • javascript直接运行在网站上
相关问题