本文爲 WebSocket 協議的第九章,本文翻譯的主要內容爲 WebSocket 安全性相關內容。html
這一章描述了一些 WebSocket 協議的可用的安全性考慮。這一章的小節描述了這些特定的安全性考慮。算法
WebSocket 協議防止在受信任的應用例如 Web 瀏覽器中執行的惡意 JavaScript 代碼,例如經過檢查Origin
頭字段(見下面)。見第 1.6 節去了解更多詳情。這種假設在更有能力的客戶端的狀況下不成立。瀏覽器
這個協議能夠被網頁中的腳本使用,也能夠經過宿主直接使用。這些宿主是表明本身的利益的,所以能夠發送假的Origin
頭字段來欺騙服務端。所以服務端對於他們正在和已知的源的腳本直接通訊的假設須要消息,而且必須認爲他們可能經過沒有預期的方式訪問。特別地,服務端不該該相信任何輸入都是有效的。緩存
示例:若是服務端使用輸入的內容做爲一部分的 SQL 查詢語句,全部的輸入文本都必須在傳遞給 SQL 服務器時進行編碼,以避免服務端受到 SQL 注入攻擊。安全
只處理特定站點,不打算處理任何 Web 頁面的數據服務器應該驗證Origin
字段是不是他們預期的。若是服務端收到的源字段是不接受的,那麼他應該經過包含 HTTP 禁止狀態碼爲 403 的請求響應做爲 WebSocket 握手的響應。服務器
當不信任的一方是 JavaScript 應用做者並存在受信任的客戶端中運行時,Origin
字段能夠避免出現這種攻擊的狀況。客戶端能夠鏈接到服務端,經過協議中的Origin
字段,肯定是否開放鏈接的權限給 JavaScript 應用。這麼作的目的不是組織非瀏覽器應用創建鏈接,而是保證在受信任的瀏覽器中可能運行的惡意 JavaScript 代碼並不會構建一個假的 WebSocket 握手。網絡
除了終端可能會成爲經過 WebSocket 被攻擊的目標以外,網絡基礎設施的另一部分,例如代理,也有多是攻擊的對象。app
這個協議發展後,經過一個實驗驗證了部署在外部的緩存服務器因爲一系列在代理上面的攻擊致使投毒。通常形式的攻擊就是在攻擊者控制下創建一個與服務端的鏈接,實現一個與 WebSocket 協議創建鏈接類似的 HTTP UPGRADE 鏈接,而後經過升級之後的鏈接發送數據,看起來就像是針對已知的特定資源(在攻擊中,這可能相似於普遍部署的腳本,用於跟蹤廣告服務網絡上的點擊或資源)進行 GET 請求。遠端服務器可能會經過一些看上去像響應數據的來響應假的 GET 請求,而後這個響應就會按照非零百分比的已部署中介緩存,所以致使緩存投毒。這個攻擊帶來的影響就是,若是一個用戶能夠正常的訪問一個攻擊者控制的網網站,那麼攻擊者能夠針對這個用戶進行緩存投毒,在相同緩存的後面其餘用戶會運行其餘源的惡意腳本,破壞 Web 安全模型。測試
爲了不對中介服務的此類攻擊,使用不符合 HTTP 的數據幀中爲應用程序的數據添加前綴是不夠的,咱們不可能詳細的檢查和測試每個不合標準的中介服務有沒有跳過這種非 HTTP 幀,或者對幀載荷處理不正確的狀況。所以,採用的防護措施是對客戶端發送給服務端的全部數據添加掩碼,這樣的話遠端的腳本(攻擊者)就不可以控制發送的數據如何出如今線路上,所以就不可以構造一條被中介誤解的 HTPT請求。網站
客戶端必須爲每一幀選擇一個新的掩碼值,使用一個不可以被應用預測到的算法來進行傳遞數據。例如,每個掩碼值能夠經過一個加密強隨機數生成器來生成。若是相同的值已經被使用過或者已經存在一種方式可以判斷出下一個值如何選擇時,攻擊這個能夠發送一個添加了掩碼的消息,來模擬一個 HTTP 請求(經過在線路上接收攻擊者但願看到的消息,使用下一個被使用的掩碼值來對數據進行添加掩碼,當客戶端使用它時,這個掩碼值能夠有效地反掩碼數據)。
當從客戶端開始傳遞第一幀時,這個幀的有效載荷(應用程序提供的數據)就不可以被客戶端應用程序修改,這個策略是很重要的。不然,攻擊者能夠發送一個都是已知值(例如所有爲 0)的初始值的很長的幀,計算收到第一部分數據時使用過的掩碼,而後修改幀中還沒有發送的數據,以便在添加掩碼時顯示爲 HTTP 請求。(這與咱們在以前的段落中描述的使用已知的值和可預測的值做爲掩碼值,其實是相同的問題。)若是另外的數據已經發送了,或者要發送的數據有所改變,那麼新的數據或者修改的數據必須使用一個新的數據幀進行發送,所以也須要選擇一個新的掩碼值。簡短來講,一旦一個幀的傳輸開始後,內容不可以被遠端的腳本(應用)修改。
受保護的威脅模型是客戶端發送看似HTTP請求的數據的模型。所以,從客戶端發送給服務端的頻道數據須要添加掩碼值。從服務端到客戶端的數據看上去像是一個請求的響應,可是,爲了完成一次請求,客戶端也須要能夠僞造請求。所以,咱們不認爲須要在雙向傳輸上添加掩碼。(服務端發送給客戶端的數據不須要添加掩碼)
儘管經過添加掩碼提供了保護,可是不兼容的 HTTP 代理仍然因爲客戶端和服務端之間不支持添加掩碼而受到這種類型的攻擊。
在從多個幀從新組裝後,對於幀大小或總消息大小具備實現和必須避免本身超過相關的多平臺特定限制帶來的影響。(例如:一個惡意的終端可能會嘗試耗盡對端的內存或者經過發送一個大的幀(例如:大小爲 2 ** 60)或發送一個長的由許多分片幀構成的流來進行拒絕服務攻擊)。這些實現應該對幀的大小和組裝事後的包的總大小有必定的限制。
這個協議在 WebSocket 握手時,沒有規定服務端可使用哪一種方式進行認證。WebSocket 服務器可使用任意 HTTP 服務器通用的認證機制,例如: Cookie、HTTP 認證或者 TLS 認證。
鏈接保密性是基於運行 TLS 的 WebSocket 協議(wss 的 URLs)。WebSocket 協議實現必須支持 TLS,而且應該在與對端進行數據傳輸時使用它。
若是在鏈接中使用 TLS,TLS帶來的鏈接的收益很是依賴於 TLS 握手時的算法的強度。例如,一些 TLS 的加密算法不提供鏈接保密性。爲了實現合理登記的保護措施,客戶端應該只使用強 TLS 算法。「Web 安全:用戶接口指南」(W3C.REC-wsc-ui-20100812)討論了什麼是強 TLS 算法。RFC5246 的附錄 A.5和附錄 D.3提供了另外的指導。
傳入的數據必須通過客戶端和服務端的認證。若是,在某個時候,一個終端面對它沒法理解的數據或者違反了這個終端定義的輸入安全規範和標準,或者這個終端在開始握手時沒有收到對應的預期值時(在客戶端請求中不正確的路徑或者源),終端應該關閉 TCP 鏈接。若是在成功的握手後收到了無效的數據,終端應該在進入關閉 WebSocket
流程前,發送一個帶有合適的狀態碼(第 7.4 節)的關閉幀。使用一個合適的狀態碼的關閉幀有助於診斷這個問題。若是這個無效的數據是在 WebSocket 握手時收到的,服務端應該響應一個合適的 HTTP 狀態碼(RFC2616)。
使用錯誤的編碼來發送數據是一類通用的安全問題。這個協議指定文本類型數據(而不是二進制或者其餘類型)的消息使用 UTF-8 編碼。雖然仍然能夠獲得長度值,但實現此協議的應用程序應使用這個長度來肯定幀實際結束的位置,發送不合理的編碼數據仍然會致使基於此協議構建的應用程序可能會致使從數據的錯誤解釋到數據丟失或潛在的安全漏洞出現。
在這個文檔中描述的 WebSocket 握手協議是不依賴任意 SHA-1 的安全屬性,流入抗衝擊性和對第二次前映像攻擊的抵抗力(就像 RFC4270 描述的同樣)。