要控制你的副檔名可以執行哪些內容,請依 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 元素並非合適的機制。
請參閱:
- 內容安全政策 (MDN 的 CSP) 。
- 清單 - 內容安全政策 收錄於 Chrome 擴充功能>參考。
預設政策限制
沒有定義 的 manifest_version 套件沒有預設的內容安全政策。
使用 manifest_version 的套件有以下預設的內容安全政策:
該政策透過三種方式限制擴充功能和應用程式來增加安全性:
評估及相關功能被停用
以下程式碼無法運作:
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、 。 原點的宿主部分必須明確指定於 https 和 extension 方案。 通用萬用字元如 https: https://*https://*.com, 和 不被允許;子網域萬用字元如 允許。https://*.example.com
公共後綴列表中的網域也被視為通用頂層網域。 若要從這些網域載入資源,必須明確列出子網域。 例如, https://*.cloudfront.net 不成立,但 https://XXXX.cloudfront.net 和 https://*.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 的腳本。
另請參閱
- 內容安全政策 (MDN 的 CSP) 。
- 清單 - 內容安全政策 收錄於 Chrome 擴充功能>參考。
注意事項
本頁部分內容基於 Google 創作與 分享 的作品,並依 據創用CC 姓名標示 4.0 國際授權條款進行修改。 原始頁面 可在此查閱。
本作品採用 創用CC 姓名標示4.0國際授權條款授權。