# 安全注意事項
本章描述了一些適用于WebSocket協議的安全注意事項。具體的安全注意事項在本章的字章節描述。
## 10.1.非瀏覽器客戶端
WebSocket協議防止惡意的JavaScript運行在一個受信任的應用內部,比如web瀏覽器,例如,通過檢查頭字段|Origin|(見下文)。更多細節請參考1.6節。在一個更強大的客戶端的情況下,這樣的假設不成立。
雖然該協議的目的是被web頁面中的腳本使用,它也可以被主機直接使用。這樣的主機按照它們自己的行為行事,因此可以發送偽造的|Origin|頭字段,騙過服務器。因此服務器應該小心,假設它們是直接與來自已知源的腳本通信,且必須考慮到它們可能以非預期方式訪問。尤其,服務器不應該相信任何輸入是有效的。
例如:如果服務器使用輸入作為SQL查詢的一部分,所有輸入文本在傳輸到SQL服務器之前應該被轉義,以免服務器受到SQL注入攻擊。
## 10.2. Origin注意事項
服務器不打算處理來自任意web頁面的輸入,但僅限于網站應該驗證|Origin|頭是一個它們盼望的源。如果源指示是服務器不可接受的,那么它應該以一個包含HTTP 403 Forbidden的狀態碼的回復響應WebSocket握手。
當不受信任方通常是一個執行在受信任的客戶端上下文中的JavaScript應用的作者時,|Origin|頭字段可以保護攻擊的情況。客戶端本身可以與服務器聯系,并通過| Origin|頭字段機制,決定是否提供JavaScript應用的這些通信權限。目的不是為了阻止非瀏覽器建立連接,而是確保受信的瀏覽器在潛在的惡意JavaScript控制下不能偽造WebSocket握手。
## 10.3.攻擊基礎設施(掩碼)
除了端點是WebSocket攻擊的目標之外,web基礎設施的其他部分,如代理,也可能是攻擊的對象。在本協議正在開發時,進行了一個實驗旨在演示一類代理上的攻擊,其導致部署在野的緩存代理中毒[討論]。一般的攻擊形式是在“攻擊者”的控制下建立一個到服務器的連接,執行類似于WebSocket協議建立連接的HTTP連接上的UPGRADE,且隨后在已經UPGRADE的連接上發送數據,看起來像一個GET請求一個特定的已知資源(在一次攻擊中,很可能會像廣泛部署的用于跟蹤點擊或一個廣告服務網絡資源的腳本)。遠程服務器響應的東西看起來像是到偽造的GET請求的一個響應,且這個響應將被一個非零百分比的部署的中間件緩存,因此使緩存中毒了。這種攻擊的靜效應將是如果能說服用戶去訪問攻擊者控制的網站,攻擊者可能使用戶和其他晚于相同緩存的用戶的緩存中毒且在其他源運行惡意腳本,影響網絡安全模型。
為避免這種部署的中間件上的攻擊,前置不兼容HTTP的和幀一起的應用提供的數據是不夠的,因為無法詳盡地發現和測試每一個不符合中間件的不跳過這樣的非HTTP幀和錯誤地假裝幀負載。
因此,采用的防御是掩碼所有從客戶端到服務器端發送的數據,使遠程腳本(攻擊者)無法控制數據如何在電線上發送,從而無法構造一個可能被中間件誤解釋的作為一個HTTP請求的消息。
客戶端必須為每一幀選擇一個新的掩碼密鑰,使用一個不能被提供數據的終端應用預測。例如,每次掩碼可以從一個強加密的隨機數生成器獲取。如果使用相同的密鑰或存在一個可預測的模式用于選擇下一個密鑰,當掩碼后,攻擊者可以發送一個消息,可能作為一個HTTP請求出現(通過交換消息,攻擊者希望觀察線上并用下一個將被使用的掩碼密鑰掩碼它,當客戶端應用它時掩碼密鑰將有效的解碼數據)。 一旦從客戶端傳輸一個幀已經開始,幀的負載(應用提供的數據)必須不能被應用修改也是必要的。
否則,攻擊者可能發送一個已知初始數據(如都是0)的長幀,一收到數據的第一部分后就開始計算使用的掩碼密鑰,當掩碼后,接著修改尚未發送的作為一個請求出現的幀中的數據(這本質上是和前面段落描述的使用一個已知的或可預測的掩碼密鑰是相同的問題)。 如果需要發送額外的數據或要發送的數據以某種方式修改了,新的或修改了的數據必須在一個新的幀中發送,那么需要一個新的掩碼密鑰。總之,一旦開始傳輸一個幀,對于遠程腳本(應用)來說,內容必須不能是可修改的。
威脅模型用來保護客戶端發送的在一個請求出現的數據。因此,需要掩碼的信道是從客戶端到服務器的數據。服務器到客戶端的數據可以作出看起來像一個響應,但為了完成這個請求,客戶端也必須有能力去偽造一個請求。因此,沒必要在兩個方向上掩碼數據(從客戶端到服務器的數據沒有掩碼)。
盡管掩碼提供了保護,對于客戶端和服務器沒有掩碼的這種類型的中毒攻擊,非兼容HTTP代理將依然是脆弱的。
## 10.4.實現特定限制
實現已經實現— 和/或特定平臺的有關幀大小或總消息大小的限制,從多個幀重新組裝后,必須保證它們自己不超過這些限制。(例如,一個惡意終端無論是通過單一的大幀(例如,2**60大小)還是通過發送一個長流的分片消息的一部分的小幀,可以設法耗盡它的對等體端點(Peer,即要攻擊的那一方)的內存或安裝一個拒絕服務攻擊)。這樣的實現應該對幀大小和和從多個幀重組后的總消息大小加以限制。
## 10.5.WebSocket客戶端驗證
本規范沒有規定任何特定的方式在WebSocket握手期間服務器可以驗證客戶端。WebSocket服務器可以使用任何客戶端對普通HTTP服務器可用的驗證機制,如Cookie,HTTP驗證,或者TLS驗證。
## 10.6.連接的保密性和完整性
連接的保密性和完整性是通過運行在TLS(wss URI)上WebSocket協議提供的。WebSocket實現必須支持TLS并應該在與它們的對等端點通信時使用它。
對于使用TLS的連接,TLS提供的受益量在很大程度上取決于在TLS握手期間協商的算法強度。例如,一些TLS加密機制不提供連接的保密性。為了實現合理級別的保護,客戶端應該僅適用強TLS算法。“Web安全上下文:用戶接口指南”[[W3C.REC-wsc-ui-20100812](http://tools.ietf.org/html/rfc6455#ref-W3C.REC-wsc-ui-20100812)]討論了什么構成強TLS算法。[[RFC5246](http://www.faqs.org/rfcs/rfc5246.html)]的[附錄A.5](http://tools.ietf.org/html/rfc6455#appendix-A.5)和[附錄D.3](http://tools.ietf.org/html/rfc6455#appendix-D.3)中提供了額外的指導。
## 10.7.處理無效數據
傳入的數據必須始終由客戶端和服務器驗證。如果,在任何時候,一個端點不理解它的數據或違反了一些端點確定的安全輸入標準,或當端點看到一個打開階段握手沒有符合它盼望的值(例如,在客戶端請求中不正確的路徑或源),端點可以終止TCP連接。如果在WebSocket握手成功后接收到了無效數據,端點應該在進行*關閉WebSocket連接*之前發送一個帶有適當狀態碼([7.4節](http://tools.ietf.org/html/rfc6455#section-7.4))的關閉幀。使用一個帶有適當狀態碼的關閉幀能幫助診斷問題。如果在WebSocket握手期間發送了無效的數據,服務器應該返回一個適當的HTTP[[RFC2616](http://tools.ietf.org/html/rfc2616)]狀態碼。使用錯誤的編碼發送文本數據是通常出現的一類安全問題。本協議規定一個Text數據類型(而不是Binary或其他類型)的消息包含UTF-8編碼的數據。雖然仍指定了長度,且實現本協議的應用應該使用長度來決定幀從哪真正結束,但以一個不當的編碼發送數據仍可能打破建立在本協議之上的應用的假設,導致從誤解釋數據到丟失數據或潛在的安全漏洞。
## 10.8.使用SHA-1的WebSocket握手
本文檔中描述的WebSocket握手不依賴于任何SHA-1安全特性,例如抗碰撞性或抗第二前像攻擊(如同[[RFC4270](http://tools.ietf.org/html/rfc4270)]中的描述)。