2011-09-21 74 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直接運行在網站上
相關問題