共用方式為


利用內容安全政策 (CSP) 來控制可執行的資源

要控制你的副檔名可以執行哪些內容,請依 manifest.json 以下語法使用 content_security_policy 該鍵及其政策字串值:

{
    ...,
    "content_security_policy": "[policy string]"
    ...
}

例如,以下是預設內容安全政策,詳述於下文 的預設政策限制

{
    ...,
    "content_security_policy": "script-src 'self'; object-src 'self'; worker-src 'self'"
    ...
}

為減少一大類潛在的跨站腳本問題,Microsoft Edge 擴充系統整合了內容安全政策 (CSP) 。 CSP 引入了一些嚴格的政策,讓擴充功能預設更安全,並讓你能夠建立並執行規則,規範擴充功能和應用程式可載入和執行的內容類型。

一般來說,CSP 是作為一個封鎖/允許清單機制,針對你的擴充套件載入或執行的資源。 為你的擴充功能制定合理的政策,能讓你仔細考慮擴充功能所需的資源,並要求瀏覽器確保這些是擴充功能唯一能存取的資源。 這些政策除了你所請求的主機權限外,還提供安全性;它們是額外的保護層,而非替代品。

相較之下,在網頁中,這類政策是透過 HTTP 標頭或 meta 元素定義的。 但在 Microsoft Edge 擴充系統中,HTTP 標頭或 meta 元素並非合適的機制。

請參閱:

預設政策限制

沒有定義 的 manifest_version 套件沒有預設的內容安全政策。

使用 manifest_version 的套件有以下預設的內容安全政策:

script-src 'self'; object-src 'self'; worker-src 'self'

該政策透過三種方式限制擴充功能和應用程式來增加安全性:

以下程式碼無法運作:

alert(eval("foo.bar.baz"));
window.setTimeout("alert('hi')", 10);
window.setInterval("alert('hi')", 10);
new Function("return foo.bar.baz");

像這樣評估 JavaScript 字串是常見的 XSS 攻擊向量。 相反地,你應該寫像這樣的程式碼:

alert(foo && foo.bar && foo.bar.baz);
window.setTimeout(function() { alert('hi'); }, 10);
window.setInterval(function() { alert('hi'); }, 10);
function() { return foo && foo.bar && foo.bar.baz };

內嵌式 JavaScript 不會被執行

內嵌式 JavaScript 不會被執行。 此限制同時禁止內嵌 <script> 區塊與內嵌事件處理程序,例如 <button onclick="...">

第一個限制消除了大量跨站腳本攻擊,讓你無法不小心執行惡意第三方提供的腳本。 不過,這確實需要你在程式碼中清楚分開內容與行為。 舉個例子可能會讓這點更清楚。 你可以嘗試以單一 pop-up.html 瀏覽器動作彈出視窗的形式寫出,內容包含以下內容:

<!doctype html>
<html>
    <head>
        <title>My Awesome Pop-up!</title>
        <script>
            function awesome() {
                // do something awesome!
            }

            function totallyAwesome() {
                // do something TOTALLY awesome!
            }

            function clickHandler(element) {
                setTimeout("awesome(); totallyAwesome()", 1000);
            }

            function main() {
                // Initialization work goes here.
            }
        </script>
    </head>
    <body onload="main();">
        <button onclick="clickHandler(this)">
            Click for awesomeness!
        </button>
    </body>
</html>

但要讓這一切如你所願運作,必須改變三件事:

  • clickHandler定義必須移入外部 JavaScript 檔案 (popup.js 該檔案可能是良好的目標) 。

  • 內嵌事件處理程序的定義必須以 來重 addEventListener 寫並擷取為 popup.js。 如果你目前 <body onload="main();">用的是像 ,可以考慮用掛鉤文件 DOMContentLoaded 事件或 load 視窗事件來取代它,視需求而定。 用前者,因為通常觸發得比較快。

  • setTimeout必須重寫該呼叫,以避免將字串"awesome(); totallyAwesome()"轉換成執行時的 JavaScript。

這些變更可能如下:

function awesome() {
    // Do something awesome!
}

function totallyAwesome() {
    // do something TOTALLY awesome!
}

function awesomeTask() {
    awesome();
    totallyAwesome();
}

function clickHandler(e) {
    setTimeout(awesomeTask, 1000);
}

function main() {
    // Initialization work goes here.
}

// Add event listeners once the DOM has fully loaded by listening for the
// `DOMContentLoaded` event on the document, and adding your listeners to
// specific elements when it triggers.
document.addEventListener('DOMContentLoaded', function () {
    document.querySelector('button').addEventListener('click', clickHandler);
    main();
});
<!doctype html>
<html>
    <head>
        <title>My Awesome Pop-up!</title>
        <script src="popup.js"></script>
    </head>
    <body>
        <button>Click for awesomeness!</button>
    </body>
</html>

僅載入本地腳本與物件資源

腳本與物件資源只能從擴充套件載入,無法從整個網頁載入。 這確保你的擴充功能只執行你特別核准的程式碼,防止主動網路攻擊者惡意重定向你的資源請求。

與其寫依賴 jQuery (或其他函式庫) 從外部 CDN 載入的程式碼,不如考慮在擴充套件中加入特定版本的 jQuery。 也就是說,代替:

<!doctype html>
<html>
    <head>
        <title>My Awesome Pop-up!</title>
        <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
    </head>
    <body>
        <button>Click for awesomeness!</button>
    </body>
</html>

改用以下方法。 下載檔案,放入你的套件中,並寫下:

<!doctype html>
<html>
    <head>
        <title>My Awesome Pop-up!</title>
        <script src="jquery.min.js"></script>
    </head>
    <body>
        <button>Click for awesomeness!</button>
    </body>
</html>

放寬預設政策

你可以允許執行以下類型的腳本:

詳情如下。

內嵌劇本

透過在政策中指定原始碼的 base64 編碼雜湊值,即可允許內嵌腳本。 此雜湊必須以所用雜湊演算法 sha256、sha384 或 sha512) (作為前綴。 舉例來說,請參見 W3C > 雜湊碼的腳本>元素<使用法。

遠端腳本

如果你需要外部 JavaScript 或物件資源,可以透過允許列出應該接受腳本的安全來源來有限度放寬政策。 確認那些以擴充功能權限提升載入的執行時資源,確實是你預期的資源,且不會被主動的網路攻擊者取代。 由於中間 人攻擊 在 HTTP 上既簡單又難以偵測,這些來源不被接受。

目前,你可以將允許清單的起源配置如下:blob、、 filesystemhttpsextension、 。 原點的宿主部分必須明確指定於 httpsextension 方案。 通用萬用字元如 https: https://*https://*.com, 和 不被允許;子網域萬用字元如 允許。https://*.example.com 公共後綴列表中的網域也被視為通用頂層網域。 若要從這些網域載入資源,必須明確列出子網域。 例如, https://*.cloudfront.net 不成立,但 https://XXXX.cloudfront.nethttps://*.XXXX.cloudfront.net 可以是 allowlisted

為了開發方便,從本地機器上的伺服器透過 HTTP 載入的資源可以是 allowlisted。 你可以在任何 或 http://localhost的移植http://127.0.0.1版本上允許 script 和 object source。

對透過 HTTP 載入資源的限制僅適用於直接執行的資源。 例如,你仍然可以自由連結 XMLHTTPRequest 任何你想要的來源;預設政策不會以任何方式限制 connect-src 其他 CSP 指令。

允許透過 HTTPS 載入 example.com 腳本資源的寬鬆政策定義可能如下:

"content_security_policy": "script-src 'self' https://example.com; object-src 'self'"

兩者皆script-srcobject-src由保單定義。 Microsoft Edge 不接受不限制每個數值至少) self (的政策。

評估過的 JavaScript

針對 eval()setInterval(String)new Function(String) 等相關功能的setTimeout(String)保單,可以透過在保單中新增unsafe-eval以下內容來放寬:

"content_security_policy": "script-src 'self' 'unsafe-eval'; object-src 'self'"

不過,你應該避免放寬政策。 這類函式是臭名昭著的 XSS 攻擊向量。

收緊預設政策

你可以根據延長期限限制,將此保單收緊,以提升安全性,但會犧牲便利性。 例如,若要指定你的擴充只能載入任何類型的資源 (影像,並) 相關擴充套件中的資源,可能適用 的 default-src 'self' 政策。

內容腳本

討論的政策適用於擴充的背景頁面和事件頁面。 內容腳本如何套用到擴充功能的內容腳本則比較複雜。

內容腳本通常不受擴充套件的 CSP 約束。 由於內容腳本不是 HTML,主要影響是即使擴充套件的 CSP 沒有指定unsafe-eval,它們仍可使用eval,雖然這並不建議。 此外,該頁面的 CSP 不適用於內容腳本。 更複雜的是 <script> 內容腳本建立並放入其執行頁面 DOM 的標籤。 這些腳本之後會被稱為 DOM 注入腳本。

DOM 注入腳本,注入後立即執行,正如你預期的那樣。 想像一個內容腳本,裡面有以下程式碼作為簡單範例:

document.write("<script>alert(1);</script>");

此內容腳本會立即document.write()alert 。 這會 不管頁面指定的政策是什麼。 然而,無論是在注入的 DOM 腳本內部,還是注入後不會立即執行的腳本,行為都會變得更複雜。

想像你的擴充功能運行在一個提供相關 CSP 的頁面上,該 CSP 指定了 script-src 'self'。 現在想像內容腳本執行以下程式碼:

document.write("<button onclick='alert(1);'>click me</button>'");

如果使用者點擊那個按鈕, onclick 腳本就不會執行。 這是因為腳本沒有立即執行,且直到 click 事件發生前才解譯的程式碼不被視為內容腳本的一部分,因此頁面的 CSP (而非限制行為) 的擴充功能。 而且因為 CSP 沒有指定 unsafe-inline,內嵌事件處理器被封鎖了。

在此情況下,正確實作所需行為的方法是從內容腳本中加入 onclick 處理器作為函式,如下:

document.write("<button id='mybutton'>click me</button>'");
var button = document.getElementById('mybutton');
button.onclick = function() {
      alert(1);
};

如果內容腳本執行以下情況,也會產生另一個類似問題:

var script = document.createElement('script');
script.innerHTML = 'alert(1);'
document.getElementById('body').appendChild(script);

此時腳本執行,警報隨即出現。 不過,請考慮這個情況:

var script = document.createElement('script');
script.innerHTML = 'eval("alert(1);")';
=document.getElementById('body').appendChild(script);

當初始腳本執行時,呼叫 的 eval 部分會被阻擋。 也就是說,雖然允許初始腳本執行時間,但腳本內的行為由頁面的 CSP 規範。 因此,根據你在擴充功能中如何撰寫 DOM 注入腳本,頁面 CSP 的變更可能會影響擴充功能的行為。

由於內容腳本不受頁面 CSP 影響,這也是個很好的理由,應該盡可能將擴充功能的行為放入內容腳本,而非注入 DOM 的腳本。

另請參閱

注意事項

本頁部分內容基於 Google 創作與 分享 的作品,並依 據創用CC 姓名標示 4.0 國際授權條款進行修改。 原始頁面 可在此查閱。

創用CC授權 本作品採用 創用CC 姓名標示4.0國際授權條款授權。