1. WebSocket特性介紹WebSocket是HTML5開始提供的一種瀏覽器與服務(wù)器間進(jìn)行全雙工通訊的網(wǎng)絡(luò)技術(shù)。WebSocket通信協(xié)議于2011年被I
WebSocket是HTML5開始提供的一種瀏覽器與服務(wù)器間進(jìn)行全雙工通訊的網(wǎng)絡(luò)技術(shù)。WebSocket通信協(xié)議于2011年被IETF定為標(biāo)準(zhǔn)RFC 6455,WebSocket API也被W3C定為標(biāo)準(zhǔn),主流的瀏覽器都已經(jīng)支持WebSocket通信。
WebSocket協(xié)議是基于TCP協(xié)議上的獨立的通信協(xié)議,在建立WebSocket通信連接前,需要使用HTTP協(xié)議進(jìn)行握手,從HTTP連接升級為WebSocket連接。瀏覽器和服務(wù)器只需要完成一次握手,兩者之間就直接可以創(chuàng)建持久性的連接,并進(jìn)行雙向數(shù)據(jù)傳輸。
WebSocket定義了兩種URI格式, “ws://“和“wss://”,類似于HTTP和HTTPS, “ws://“使用明文傳輸,默認(rèn)端口為80,”wss://“使用TLS加密傳輸,默認(rèn)端口為443。
-
ws-URI : "ws://host[:port]path[?query]"
-
wss-URI : "wss://host[:port]path[?query]"
WebSocket 握手階段,需要用到一些HTTP頭,升級HTTP連接為WebSocket連接如下表所示。
| HTTP頭 | 是否必須 | 解釋 |
|---|---|---|
| Host | 是 | 服務(wù)端主機(jī)名 |
| Upgrade | 是 | 固定值,”websocket” |
| Connection | 是 | 固定值,”Upgrade” |
| Sec-WebSocket-Key | 是 | 客戶端臨時生成的16字節(jié)隨機(jī)值, base64編碼 |
| Sec-WebSocket-Version | 是 | WebSocket協(xié)議版本 |
| Origin | 否 | 可選, 發(fā)起連接請求的源 |
| Sec-WebSocket-Accept | 是(服務(wù)端) | 服務(wù)端識別連接生成的隨機(jī)值 |
| Sec-WebSocket-Protocol | 否 | 可選,客戶端支持的協(xié)議 |
| Sec-WebSocket-Extensions | 否 | 可選, 擴(kuò)展字段 |
一次完整的握手連接如下圖:
一旦服務(wù)器端返回 101 響應(yīng),即可完成 WebSocket 協(xié)議切換。服務(wù)器端可以基于相同端口,將通信協(xié)議從 http://或 https:// 切換到 ws://或 wss://。協(xié)議切換完成后,瀏覽器和服務(wù)器端可以使用 WebSocket API 互相發(fā)送和收取文本和二進(jìn)制消息。
WebSocket作為一種通信協(xié)議引入到Web應(yīng)用中,并不會解決Web應(yīng)用中存在的安全問題,因此WebSocket應(yīng)用的安全實現(xiàn)是由開發(fā)者或服務(wù)端負(fù)責(zé)。這就要求開發(fā)者了解WebSocket應(yīng)用潛在的安全風(fēng)險,以及如何做到安全開發(fā)規(guī)避這些安全問題。
WebSocket 協(xié)議沒有規(guī)定服務(wù)器在握手階段應(yīng)該如何認(rèn)證客戶端身份。服務(wù)器可以采用任何 HTTP 服務(wù)器的客戶端身份認(rèn)證機(jī)制,如 cookie認(rèn)證,HTTP 基礎(chǔ)認(rèn)證,TLS 身份認(rèn)證等。在WebSocket應(yīng)用認(rèn)證實現(xiàn)上面臨的安全問題和傳統(tǒng)的Web應(yīng)用認(rèn)證是相同的,如:CVE-2015-0201, Spring框架的Java SockJS客戶端生成可預(yù)測的會話ID,攻擊者可利用該漏洞向其他會話發(fā)送消息; CVE-2015-1482, Ansible Tower未對用戶身份進(jìn)行認(rèn)證,遠(yuǎn)程攻擊者通過websocket連接獲取敏感信息。
同認(rèn)證一樣,WebSocket協(xié)議沒有指定任何授權(quán)方式,應(yīng)用程序中用戶資源訪問等的授權(quán)策略由服務(wù)端或開發(fā)者實現(xiàn)。WebSocket應(yīng)用也會存在和傳統(tǒng)Web應(yīng)用相同的安全風(fēng)險,如:垂直權(quán)限提升和水平權(quán)限提升。
WebSocket使用基于源的安全模型,在發(fā)起WebSocket握手請求時,瀏覽器會在請求中添加一個名為Origin的HTTP頭,Oringin字段表示發(fā)起請求的源,以此來防止未經(jīng)授權(quán)的跨站點訪問請求。WebSocket 的客戶端不僅僅局限于瀏覽器,因此 WebSocket 規(guī)范沒有強(qiáng)制規(guī)定握手階段的 Origin 頭是必需的,并且WebSocket不受瀏覽器同源策略的限制。如果服務(wù)端沒有針對Origin頭部進(jìn)行驗證可能會導(dǎo)致跨站點WebSocket劫持攻擊。該漏洞最早在 2013 年被Christian Schneider 發(fā)現(xiàn)并公開,Christian 將之命名為跨站點 WebSocket 劫持 (Cross Site WebSocket Hijacking)(CSWSH)。跨站點 WebSocket 劫持危害大,但容易被開發(fā)人員忽視。相關(guān)案例可以參考: IPython Notebook(CVE-2014-3429), OpenStack Compute(CVE-2015-0259), Zeppelin WebSocket服務(wù)器等跨站W(wǎng)ebSocket劫持。
上圖展示了跨站W(wǎng)ebSocket劫持的過程,某個用戶已經(jīng)登錄了WebSocket應(yīng)用程序,如果他被誘騙訪問了某個惡意網(wǎng)頁,而惡意網(wǎng)頁中植入了一段js代碼,自動發(fā)起 WebSocket 握手請求跟目標(biāo)應(yīng)用建立 WebSocket 連接。注意到,Origin 和 Sec-WebSocket-Key 都是由瀏覽器自動生成的,瀏覽器再次發(fā)起請求訪問目標(biāo)服務(wù)器會自動帶上cookie 等身份認(rèn)證參數(shù)。如果服務(wù)器端沒有檢查 Origin頭,則該請求會成功握手切換到 WebSocket 協(xié)議,惡意網(wǎng)頁就可以成功繞過身份認(rèn)證連接到 WebSocket 服務(wù)器,進(jìn)而竊取到服務(wù)器端發(fā)來的信息,或者發(fā)送偽造信息到服務(wù)器端篡改服務(wù)器端數(shù)據(jù)。與傳統(tǒng)跨站請求偽造(CSRF)攻擊相比,CSRF 主要是通過惡意網(wǎng)頁悄悄發(fā)起數(shù)據(jù)修改請求,而跨站 WebSocket 偽造攻擊不僅可以修改服務(wù)器數(shù)據(jù),還可以控制整個雙向通信通道。也正是因為這個原因,Christian 將這個漏洞命名為劫持(Hijacking),而不是請求偽造(Request Forgery)。
理解了跨站W(wǎng)ebSocket劫持攻擊的原理和過程,那么如何防范這種攻擊呢?處理也比較簡單,在服務(wù)器端的代碼中增加 對Origin頭的檢查,如果客戶端發(fā)來的 Origin 信息來自不同域,服務(wù)器端可以拒絕該請求。但是僅僅檢查 Origin 仍然是不夠安全的,惡意網(wǎng)頁可以偽造Origin頭信息,繞過服務(wù)端對Origin頭的檢查,更完善的解決方案可以借鑒CSRF的解決方案-令牌機(jī)制。
WebSocket設(shè)計為面向連接的協(xié)議,可被利用引起客戶端和服務(wù)器端拒絕服務(wù)攻擊,相關(guān)案例可參考: F5 BIG-IP遠(yuǎn)程拒絕服務(wù)漏洞(CVE-2016-9253)。
(1). 客戶端拒絕服務(wù)
WebSocket連接限制不同于HTTP連接限制,和HTTP相比,WebSocket有一個更高的連接限制,不同的瀏覽器有自己特定的最大連接數(shù),如:火狐瀏覽器默認(rèn)最大連接數(shù)為200。通過發(fā)送惡意內(nèi)容,用盡允許的所有Websocket連接耗盡瀏覽器資源,引起拒絕服務(wù)。
(2). 服務(wù)器端拒絕服務(wù)
WebSocket建立的是持久連接,只有客戶端或服務(wù)端其中一發(fā)提出關(guān)閉連接的請求,WebSocket連接才關(guān)閉,因此攻擊者可以向服務(wù)器發(fā)起大量的申請建立WebSocket連接的請求,建立持久連接,耗盡服務(wù)器資源,引發(fā)拒絕服務(wù)。針對這種攻,可以通過設(shè)置單IP可建立連接的最大連接數(shù)的方式防范。攻擊者還可以通過發(fā)送一個單一的龐大的數(shù)據(jù)幀(如, 2^16),或者發(fā)送一個長流的分片消息的小幀,來耗盡服務(wù)器的內(nèi)存,引發(fā)拒絕服務(wù)攻擊, 針對這種攻擊,通過限制幀大小和多個幀重組后的總消息大小的方式防范。
WebSocket使用HTTP或HTTPS協(xié)議進(jìn)行握手請求,在使用HTTP協(xié)議的情況下,若存在中間人可以嗅探HTTP流量,那么中間人可以獲取并篡改WebSocket握手請求,通過偽造客戶端信息與服務(wù)器建立WebSocket連接,如下圖所示。防范這種攻擊,需要在加密信道上建立WebSocket連接,使用HTTPS協(xié)議發(fā)起握手請求。
WebSocket應(yīng)用和傳統(tǒng)Web應(yīng)用一樣,都需要對輸入進(jìn)行校驗,來防范來客戶端的XSS攻擊,服務(wù)端的SQL注入,代碼注入等攻擊。
Websocket是一個基于TCP的HTML5的新協(xié)議,可以實現(xiàn)瀏覽器和服務(wù)器之間的全雙工通訊。在即時通訊等應(yīng)用中,WebSocket具有很大的性能優(yōu)勢, 并且非常適合全雙工通信,但是,和任何其他技術(shù)一樣,開發(fā)WebSocket應(yīng)用也需要考慮潛在的安全風(fēng)險。
微信掃碼關(guān)注 億華聯(lián)眾 公眾號