概述
本文為 WebSocket 協議的第九章,本文翻譯的主要內容為 WebSocket 擴充套件相關內容。
有興趣瞭解該文件之前幾章內容的同學可以見:
- 【譯】WebSocket 協議——摘要( Abstract )
- 【譯】WebSocket 協議第一章——介紹( Introduction )
- 【譯】WebSocket 協議第二章——一致性要求( Conformance Requirements )
- 【譯】WebSocket 協議第三章——WebSocket網址( WebSocket URIs )
- 【譯】WebSocket 協議第四章——連線握手( Opening Handshake )
- 【譯】WebSocket 協議第五章——資料幀(Data Framing)
- 【譯】WebSocket 協議第六章——傳送與接收訊息(Sending and Receiving Data)
- 【譯】 WebSocket 協議第七章——關閉連線(Closing the Connection)
- 【譯】 WebSocket 協議第八章——錯誤處理(Error Handling)
- 【譯】 WebSocket 協議第九章——擴充套件(Extension)
10 安全性考慮(協議正文)
這一章描述了一些 WebSocket 協議的可用的安全性考慮。這一章的小節描述了這些特定的安全性考慮。
10.1 非瀏覽器客戶端
WebSocket 協議防止在受信任的應用例如 Web 瀏覽器中執行的惡意 JavaScript 程式碼,例如通過檢查Origin
頭欄位(見下面)。見第 1.6 節去了解更多詳情。這種假設在更有能力的客戶端的情況下不成立。
這個協議可以被網頁中的指令碼使用,也可以通過宿主直接使用。這些宿主是代表自己的利益的,因此可以傳送假的Origin
頭欄位來欺騙服務端。因此服務端對於他們正在和已知的源的指令碼直接通訊的假設需要訊息,並且必須認為他們可能通過沒有預期的方式訪問。特別地,服務端不應該相信任何輸入都是有效的。
示例:如果服務端使用輸入的內容作為一部分的 SQL 查詢語句,所有的輸入文字都必須在傳遞給 SQL 伺服器時進行編碼,以免服務端受到 SQL 注入攻擊。
10.2 源考慮
只處理特定站點,不打算處理任何 Web 頁面的資料伺服器應該驗證Origin
欄位是否是他們預期的。如果服務端收到的源欄位是不接受的,那麼他應該通過包含 HTTP 禁止狀態碼為 403 的請求響應作為 WebSocket 握手的響應。
當不信任的一方是 JavaScript 應用作者並存在受信任的客戶端中執行時,Origin
欄位可以避免出現這種攻擊的情況。客戶端可以連線到服務端,通過協議中的Origin
欄位,確定是否開放連線的許可權給 JavaScript 應用。這麼做的目的不是組織非瀏覽器應用建立連線,而是保證在受信任的瀏覽器中可能執行的惡意 JavaScript 程式碼並不會構建一個假的 WebSocket 握手。
10.3 基礎設施攻擊(新增掩碼)
除了終端可能會成為通過 WebSocket 被攻擊的目標之外,網路基礎設施的另外一部分,例如代理,也有可能是攻擊的物件。
這個協議發展後,通過一個實驗驗證了部署在外部的快取伺服器由於一系列在代理上面的攻擊導致投毒。一般形式的攻擊就是在攻擊者控制下建立一個與服務端的連線,實現一個與 WebSocket 協議建立連線相似的 HTTP UPGRADE 連線,然後通過升級以後的連線傳送資料,看起來就像是針對已知的特定資源(在攻擊中,這可能類似於廣泛部署的指令碼,用於跟蹤廣告服務網路上的點選或資源)進行 GET 請求。遠端伺服器可能會通過一些看上去像響應資料的來響應假的 GET 請求,然後這個響應就會按照非零百分比的已部署中介快取,因此導致快取投毒。這個攻擊帶來的影響就是,如果一個使用者可以正常的訪問一個攻擊者控制的網網站,那麼攻擊者可以針對這個使用者進行快取投毒,在相同快取的後面其他使用者會執行其他源的惡意指令碼,破壞 Web 安全模型。
為了避免對中介服務的此類攻擊,使用不符合 HTTP 的資料幀中為應用程式的資料新增字首是不夠的,我們不可能詳細的檢查和測試每一個不合標準的中介服務有沒有跳過這種非 HTTP 幀,或者對幀載荷處理不正確的情況。因此,採用的防禦措施是對客戶端傳送給服務端的所有資料新增掩碼,這樣的話遠端的指令碼(攻擊者)就不能夠控制傳送的資料如何出現線上路上,因此就不能夠構造一條被中介誤解的 HTPT請求。
客戶端必須為每一幀選擇一個新的掩碼值,使用一個不能夠被應用預測到的演算法來進行傳遞資料。例如,每一個掩碼值可以通過一個加密強隨機數生成器來生成。如果相同的值已經被使用過或者已經存在一種方式能夠判斷出下一個值如何選擇時,攻擊這個可以傳送一個新增了掩碼的訊息,來模擬一個 HTTP 請求(通過線上路上接收攻擊者希望看到的訊息,使用下一個被使用的掩碼值來對資料進行新增掩碼,當客戶端使用它時,這個掩碼值可以有效地反掩碼資料)。
當從客戶端開始傳遞第一幀時,這個幀的有效載荷(應用程式提供的資料)就不能夠被客戶端應用程式修改,這個策略是很重要的。否則,攻擊者可以傳送一個都是已知值(例如全部為 0)的初始值的很長的幀,計算收到第一部分資料時使用過的掩碼,然後修改幀中尚未傳送的資料,以便在新增掩碼時顯示為 HTTP 請求。(這與我們在之前的段落中描述的使用已知的值和可預測的值作為掩碼值,實際上是相同的問題。)如果另外的資料已經傳送了,或者要傳送的資料有所改變,那麼新的資料或者修改的資料必須使用一個新的資料幀進行傳送,因此也需要選擇一個新的掩碼值。簡短來說,一旦一個幀的傳輸開始後,內容不能夠被遠端的指令碼(應用)修改。
受保護的威脅模型是客戶端傳送看似HTTP請求的資料的模型。因此,從客戶端傳送給服務端的頻道資料需要新增掩碼值。從服務端到客戶端的資料看上去像是一個請求的響應,但是,為了完成一次請求,客戶端也需要可以偽造請求。因此,我們不認為需要在雙向傳輸上新增掩碼。(服務端傳送給客戶端的資料不需要新增掩碼)
儘管通過新增掩碼提供了保護,但是不相容的 HTTP 代理仍然由於客戶端和服務端之間不支援新增掩碼而受到這種型別的攻擊。
10.4 指定實現的限制
在從多個幀重新組裝後,對於幀大小或總訊息大小具有實現和必須避免自己超過相關的多平臺特定限制帶來的影響。(例如:一個惡意的終端可能會嘗試耗盡對端的記憶體或者通過傳送一個大的幀(例如:大小為 2 ** 60)或傳送一個長的由許多分片幀構成的流來進行拒絕服務攻擊)。這些實現應該對幀的大小和組裝過後的包的總大小有一定的限制。
10.5 WebSocket 客戶端認證
這個協議在 WebSocket 握手時,沒有規定服務端可以使用哪種方式進行認證。WebSocket 伺服器可以使用任意 HTTP 伺服器通用的認證機制,例如: Cookie、HTTP 認證或者 TLS 認證。
10.6 連線保密性和完整性
連線保密性是基於執行 TLS 的 WebSocket 協議(wss 的 URLs)。WebSocket 協議實現必須支援 TLS,並且應該在與對端進行資料傳輸時使用它。
如果在連線中使用 TLS,TLS帶來的連線的收益非常依賴於 TLS 握手時的演算法的強度。例如,一些 TLS 的加密演算法不提供連線保密性。為了實現合理登記的保護措施,客戶端應該只使用強 TLS 演算法。“Web 安全:使用者介面指南”(W3C.REC-wsc-ui-20100812)討論了什麼是強 TLS 演算法。RFC5246 的附錄 A.5和附錄 D.3提供了另外的指導。
10.7 處理無用資料
傳入的資料必須經過客戶端和服務端的認證。如果,在某個時候,一個終端面對它無法理解的資料或者違反了這個終端定義的輸入安全規範和標準,或者這個終端在開始握手時沒有收到對應的預期值時(在客戶端請求中不正確的路徑或者源),終端應該關閉 TCP 連線。如果在成功的握手後收到了無效的資料,終端應該在進入關閉 WebSocket
流程前,傳送一個帶有合適的狀態碼(第 7.4 節)的關閉幀。使用一個合適的狀態碼的關閉幀有助於診斷這個問題。如果這個無效的資料是在 WebSocket 握手時收到的,服務端應該響應一個合適的 HTTP 狀態碼(RFC2616)。
使用錯誤的編碼來傳送資料是一類通用的安全問題。這個協議指定文字型別資料(而不是二進位制或者其他型別)的訊息使用 UTF-8 編碼。雖然仍然可以得到長度值,但實現此協議的應用程式應使用這個長度來確定幀實際結束的位置,傳送不合理的編碼資料仍然會導致基於此協議構建的應用程式可能會導致從資料的錯誤解釋到資料丟失或潛在的安全漏洞出現。
10.8 在 WebSocket 握手中使用 SHA-1
在這個文件中描述的 WebSocket 握手協議是不依賴任意 SHA-1 的安全屬性,流入抗衝擊性和對第二次前映像攻擊的抵抗力(就像 RFC4270 描述的一樣)。