在新型網頁應用程式中安全地代管使用者資料

David Dworken
David Dworken

許多網頁應用程式都需要顯示由使用者控制的內容。這項作業可以是簡單的使用者上傳圖片 (例如個人資料相片),也可以是複雜的使用者控管 HTML 轉譯作業 (例如網頁開發教學課程)。這一直是難以安全執行的作業,因此我們致力於尋找可套用於大多數類型網頁應用程式的簡單安全解決方案。

如要安全地提供使用者控管的內容,傳統做法是使用所謂的沙箱網域。基本概念是,如果應用程式的主網域為 example.com,您可以在 exampleusercontent.com 上提供所有不受信任的內容。由於這兩個網域是跨網站,因此 exampleusercontent.com 上的任何惡意內容都不會影響 example.com
這種方法可用於安全地提供所有類型的不受信任內容,包括圖片、下載內容和 HTML。雖然圖片或下載內容似乎不需要使用這項功能,但這麼做有助於避免內容嗅探的風險,尤其是在舊版瀏覽器中。
沙箱網域在業界廣泛使用,且長期以來運作良好。但這類服務有兩個主要缺點:

  • 應用程式通常需要限制內容存取權,只允許單一使用者存取,因此必須實作驗證和授權機制。由於沙箱網域刻意不與主要應用程式網域共用 Cookie,因此要安全地執行這項操作非常困難。如要支援驗證,網站必須使用功能網址,或是為沙箱網域設定個別的驗證 Cookie。在現代網際網路中,許多瀏覽器都會預設限制跨網站 Cookie,因此第二種方法特別容易出問題。
  • 雖然使用者內容會與主要網站分開,但仍會與其他使用者內容分開。這會導致惡意使用者內容攻擊沙箱網域中的其他資料 (例如透過讀取相同來源的資料)。

值得一提的是,沙箱網域可將資源明確劃分至隔離的網域,因此有助於降低網路釣魚風險。

提供使用者內容的現代化解決方案

隨著網路的演進,現在有更簡單、更安全的方式來提供不受信任的內容。這裡有許多不同的做法,因此我們將概略說明 Google 目前廣泛使用的兩種解決方案。

方法 1:提供閒置使用者內容

如果網站只需要提供非活動使用者內容 (也就是非 HTML 或 JavaScript 的內容,例如圖片和下載內容),現在無須使用隔離的沙箱網域,也能安全地執行這項操作。有兩個重要步驟:

  • 請一律將 Content-Type 標頭設為所有瀏覽器都支援的知名 MIME 類型,並保證不含有活動內容 (如有疑慮,application/octet-stream 是安全的選擇)。
  • 此外,請務必設定下列回應標頭,確保瀏覽器能完全隔離回應。
回應標頭 Purpose

X-Content-Type-Options: nosniff

防止內容嗅探

Content-Disposition: attachment; filename="download"

觸發下載作業,而非轉譯作業

Content-Security-Policy: sandbox

將內容置入沙箱,就像是在個別網域中放送一樣

Content-Security-Policy: default-src ‘none'

停用 JavaScript 執行作業 (以及任何子資源的納入)

Cross-Origin-Resource-Policy: same-site

防止網頁納入跨網站

這組標頭可確保應用程式只能將回應載入為子資源,或由使用者下載為檔案。此外,標頭可透過 CSP 沙箱標頭和 default-src 限制,提供多層防護機制,防止瀏覽器發生錯誤。整體來說,上述設定可讓您充分放心,以這種方式提供的回應不會導致注入或隔離安全漏洞。

縱深防禦

雖然上述解決方案通常已足以防範 XSS,但您仍可採取其他強化措施,為應用程式提供額外的安全防護:

  • 設定 X-Content-Security-Policy: sandbox 標頭,以便與 IE11 相容。
  • 設定 Content-Security-Policy: frame-ancestors 'none' 標頭,禁止嵌入端點。
  • 在隔離的子網域上發布沙箱使用者內容,方法如下:
    • 在隔離的子網域上放送使用者內容 (例如 Google 使用 product.usercontent.google.com 等網域)。
    • 設定 Cross-Origin-Opener-Policy: same-originCross-Origin-Embedder-Policy: require-corp 即可啟用跨來源隔離

方法 2:提供活躍使用者內容

您也可以安全地提供主動內容 (例如 HTML 或 SVG 圖片),而不會出現傳統沙箱網域方法的缺點。
最簡單的做法是利用 Content-Security-Policy: sandbox 標頭,告知瀏覽器隔離回應。雖然目前並非所有網頁瀏覽器都會為沙箱文件實作程序隔離功能,但瀏覽器程序模型持續精進後,沙箱內容與嵌入應用程式的分離效果可能會有所改善。如果 SpectreJS轉譯器遭到入侵攻擊不在威脅模型中,那麼使用 CSP 沙箱可能就足以解決問題。
Google 開發的解決方案可透過改良沙箱網域的概念,完全隔離不受信任的活動內容。核心概念如下:

  • 建立新的沙箱網域,並新增至公開後置字串清單。舉例來說,您可以將 exampleusercontent.com 新增至 PSL,確保 foo.exampleusercontent.combar.exampleusercontent.com 是跨網站,因此彼此完全隔離。
  • *.exampleusercontent.com/shim 相符的網址都會導向靜態墊片檔案。這個墊片檔案包含簡短的 HTML 和 JavaScript 程式碼片段,可監聽 message 事件處理常式,並轉譯收到的任何內容。
  • 為使用此功能,產品會建立 iframe 或彈出式視窗至 $RANDOM_VALUE.exampleusercontent.com/shim,並使用 postMessage 將不受信任的內容傳送至 shim 進行轉譯。
  • 轉譯後的內容會轉換為 Blob,並在沙箱 iframe 中轉譯。

與傳統沙箱網域做法相比,這可確保所有內容在單一網站上完全隔離。而且,由於主要應用程式會負責擷取要轉譯的資料,因此不必再使用功能網址。

結論

這兩種解決方案可搭配使用,讓您從 googleusercontent.com 等傳統沙箱網域遷移至更安全的解決方案,以便封鎖第三方 Cookie。在 Google,我們已將許多產品遷移至這些解決方案,並且預計在明年進行更多遷移作業。