電腦版的 Chrome 67 預設啟用網站隔離這項新功能。這篇文章將說明網站隔離的意義、重要性,以及網頁程式開發人員應留意哪些原因。
什麼是網站隔離?
網際網路可用來觀看貓咪影片、管理加密貨幣錢包等等,而且不想讓 fluffycats.example
取得您珍貴的加密貨幣!幸好,根據 Same-Origin Policy,網站通常無法在瀏覽器中存取彼此的資料。不過,惡意網站可能會試圖略過這項政策,藉此攻擊其他網站,有時也會在強制執行相同來源政策的瀏覽器程式碼中發現安全性錯誤。Chrome 團隊致力盡快修正這類錯誤。
網站隔離是 Chrome 中的一項安全性功能,可提供額外的防禦措施,降低這類攻擊成功機率。這會確保來自不同網站的網頁永遠放進不同的處理程序中,每個程序都是在沙箱中執行,以限製程序允許執行的作業。此外,這麼做也會阻止程序接收其他網站中特定類型的機密資料。因此,藉由網站隔離,惡意網站更難使用推測端管道攻擊 (例如 Spectre) 竊取其他網站的資料。隨著 Chrome 團隊完成額外違規處置,即使攻擊者的網頁有機會在自己的程序中破壞部分規則,網站隔離功能也能發揮作用。
網站隔離功能會讓不受信任的網站更難在其他網站上存取或竊取帳戶中的資訊。這項機制可以防範各種安全性錯誤,例如 最新的 Meltdown 和 Spectre 旁路攻擊。
如要進一步瞭解網站隔離,請參閱 Google 安全性網誌上的文章。
跨來源讀取封鎖
即使所有跨網站網頁都進入不同的程序,網頁仍可正常要求部分跨網站子資源,例如圖片和 JavaScript。惡意網頁可能會使用 <img>
元素載入含有機密資料 (例如銀行餘額) 的 JSON 檔案:
<img src="https://your-bank.example/balance.json" />
<!-- Note: the attacker refused to add an `alt` attribute, for extra evil points. -->
在未使用網站隔離的情況下,JSON 檔案的內容會傳送至轉譯器程序的記憶體,此時轉譯器會發現它不是有效的圖片格式,因此無法轉譯圖片。然而,攻擊者可能會利用 Spectre 等漏洞,或許會讀取該記憶體區塊。
除了使用 <img>
以外,攻擊者也可能使用 <script>
將機密資料提交至記憶體:
<script src="https://your-bank.example/balance.json"></script>
跨來源讀取封鎖 (或稱 CORB) 是一項新的安全性功能,可避免 balance.json
的內容根據 MIME 類型輸入轉譯器程序記憶體的記憶體。
讓我們進一步瞭解 CORB 的運作方式。網站可以向伺服器要求兩種類型的資源:
- 資料資源,例如 HTML、XML 或 JSON 文件
- 媒體資源,例如圖片、JavaScript、CSS 或字型
網站可以從其本身來源,或來自具有許可 CORS 標頭的其他來源 (例如 Access-Control-Allow-Origin: *
) 接收資料資源。另一方面,即使沒有許可的 CORS 標頭,也可以從任何來源納入媒體資源。
如果發生下列情況,CORB 會禁止轉譯器程序接收跨來源資料資源 (即 HTML、XML 或 JSON):
- 資源含有
X-Content-Type-Options: nosniff
標頭 - CORS 未明確允許存取資源
如果跨來源資料資源未設定 X-Content-Type-Options: nosniff
標頭,CORB 會嘗試監聽回應主體,以判斷該資源是 HTML、XML 或 JSON。由於部分網路伺服器設定錯誤,而提供圖片做為 text/html
(例如圖片),因此這是必要條件。
遭到 CORB 政策封鎖的資料資源會顯示為空白,但要求仍會在背景執行。因此,惡意網頁在竊取的過程中,往往很難將跨網站資料擷取到。
為達到最佳安全性並充分發揮 CORB 的效益,建議您使用下列幾點:
- 請使用正確的
Content-Type
標頭標示回應。(例如,HTML 資源應以text/html
提供、採用 JSON MIME 類型的 JSON 資源,以及採用 XML MIME 類型的 XML 資源。 - 使用
X-Content-Type-Options: nosniff
標頭選擇停用抽樣功能。如果沒有這個標頭,Chrome 會執行快速內容分析來確認類型正確無誤,但由於這個原則會導致回應,以避免封鎖 JavaScript 檔案等項目,因此您可以明確採取措施,自行採取正確的做法。
詳情請參閱適用於網頁開發人員的 CORB 文章或我們的 CORB 深入說明。
網頁開發人員為何應該重視網站隔離?
網站隔離是瀏覽器幕後的大多數功能,不會直接提供給網頁程式開發人員。例如沒有新的網路公開 API 可以學習。一般來說,無論是否包含網站隔離功能,網頁都不應分辨出網頁有何差異。
但這項規則有些例外。啟用網站隔離功能會帶來幾項可能影響網站的副作用。我們備有已知網站隔離問題清單,將在下方列出最重要的問題。
整頁版面配置不再同步
使用網站隔離功能時,系統不再保證整頁版面配置會同步,因為網頁頁框現在可能會分散到多個程序。假如網頁假設版面配置變更會立即套用至頁面的所有影格,就可能受到影響。
舉例來說,假設名為 fluffykittens.example
的網站與 social-widget.example
代管的社交小工具進行通訊:
<!-- https://fluffykittens.example/ -->
<iframe src="https://social-widget.example/" width="123"></iframe>
<script>
const iframe = document.querySelector('iframe');
iframe.width = 456;
iframe.contentWindow.postMessage(
// The message to send:
'Meow!',
// The target origin:
'https://social-widget.example'
);
</script>
首先,社交小工具的 <iframe>
寬度為 123
像素。但接著,FluffyKittens 頁面會將寬度變更為 456
像素 (觸發版面配置),並傳送訊息至社交小工具,其中程式碼如下:
<!-- https://social-widget.example/ -->
<script>
self.onmessage = () => {
console.log(document.documentElement.clientWidth);
};
</script>
只要社交小工具透過 postMessage
API 收到訊息,就會記錄其根 <html>
元素的寬度。
系統會記錄哪個寬度值?在 Chrome 啟用網站隔離功能前,答案為 456
。存取 document.documentElement.clientWidth
會強製版面配置 (以前在 Chrome 啟用網站隔離前進行同步)。不過,啟用網站隔離功能後,跨來源社交小工具重新版面配置功能現在會在獨立的程序中以非同步方式進行。因此,答案現在也可以是 123
,即舊的 width
值。
如果網頁變更跨來源 <iframe>
的大小,然後傳送 postMessage
給該網頁,而網站隔離接收頁框在收到訊息時,接收影格可能還無法知道新大小。一般而言,如果網頁假設版面配置變更會立即套用至頁面上的所有影格,就可能破壞頁面。
在這個特定範例中,更可靠的解決方案會在上層頁框中設定 width
,並透過監聽 resize
事件偵測 <iframe>
中的變化。
卸載處理常式可能會更常逾時
瀏覽或關閉頁框時,舊文件以及其中內嵌的任何子頁框文件都會執行 unload
處理常式。如果新導覽作業是在相同的轉譯器程序 (例如相同來源導覽) 發生,則舊文件及其子頁框的 unload
處理常式可以任意執行很長的時間,然後才允許提交新導覽。
addEventListener('unload', () => {
doSomethingThatMightTakeALongTime();
});
在這種情況下,所有影格中的 unload
處理常式都非常可靠。
不過,即使沒有網站隔離功能,部分主要影格導覽仍會進行跨程序,而這會影響卸載處理常式行為。舉例來說,如果您在網址列中輸入網址,以便從 old.example
導覽至 new.example
,則 new.example
導覽會在新的程序中進行。顯示 new.example
頁面後,old.example
及其子頁框的卸載處理常式會在背景中執行,而如果舊的卸載處理常式未於特定逾時期限內完成,就會終止。old.example
由於卸載處理常式可能不會在逾時前完成,因此卸載行為較不可靠。
啟用網站隔離功能後,所有跨網站瀏覽作業都會成為跨網站瀏覽程序,因此不同網站的文件不會彼此共用處理程序。因此,上述情況適用於更多情況,<iframe>
中的卸載處理常式通常具有上述的背景和逾時行為。
網站隔離帶來的另一個差異是,卸載處理常式新的平行排序:在不使用網站隔離的情況下,卸載處理常式會以嚴格的由上而下順序執行。但有了網站隔離功能,卸載處理常式在不同程序間會平行執行。
這些是啟用網站隔離功能的基本影響。Chrome 團隊正在努力提高常見用途的卸載處理常式穩定性 (可能的話)。我們也發現有些錯誤,子頁框卸載處理常式還無法使用某些功能,目前正設法解決問題。
卸載處理常式的一個重要案例是傳送工作階段結束連線偵測 (ping)。做法通常如下:
addEventListener('pagehide', () => {
const image = new Image();
img.src = '/end-of-session';
});
基於這項變更,更好的做法是改用 navigator.sendBeacon
:
addEventListener('pagehide', () => {
navigator.sendBeacon('/end-of-session');
});
如果您需要進一步控管要求,可以使用 Fetch API 的 keepalive
選項:
addEventListener('pagehide', () => {
fetch('/end-of-session', {keepalive: true});
});
結論
網站隔離功能會將每個網站隔離至獨立程序,讓不受信任的網站更難在其他網站上存取或竊取您帳戶中的資訊。因此,CORB 會嘗試將機密資料資源移出轉譯器程序。上述建議可確保您充分運用這些全新的安全防護功能。
感謝 Alex Moshchuk、 Charlie Reis、 Jason Miller、 Nasko Oskov、Philip Walton、Shubhie Panicker 和 Thomas Steiner 是閱讀本文的草稿版本,並提供意見回饋。