01-websocket簡介及抓包分析

01-ws框架測試

1 websocket簡介

websocket是一種網絡傳輸協議,可在單個tcp鏈接上進行全雙工通信,位於OSI模型的應用層。

WebSocket 與 HTTP/2 一樣,都是爲了解決 HTTP 某方面的缺陷而誕生的。HTTP/2 針對的是“隊頭阻塞”,而 WebSocket 針對的是“請求 - 應答”通信模式。

WebSocket使得客戶端和服務器之間的數據交換變得更加簡單,允許服務端主動向客戶端推送數據。在WebSocket API中,瀏覽器和服務器只需要完成一次握手,兩者之間就可以創建持久性的連接,並進行雙向數據傳輸。

WebSocket協議在2011年由IETF標準化爲RFC 6455,後由RFC 7936補充規範。

  • RFC6455
  • RFC7936

WebSocket是一種與HTTP不同的協議。兩者都位於OSI模型的應用層,並且都依賴於傳輸層的TCP協議。 雖然它們不同,但RFC 6455規定:“WebSocket設計爲通過80和443端口工作,以及支持HTTP代理和中介”,從而使其與HTTP協議兼容。 爲了實現兼容性,WebSocket握手使用HTTP Upgrade頭[1]從HTTP協議更改爲WebSocket協議。

WebSocket協議支持Web瀏覽器(或其他客戶端應用程序)與Web服務器之間的交互,具有較低的開銷,便於實現客戶端與服務器的實時數據傳輸。 服務器可以通過標準化的方式來實現,而無需客戶端首先請求內容,並允許消息在保持連接打開的同時來回傳遞。通過這種方式,可以在客戶端和服務器之間進行雙向持續對話。 通信通過TCP端口80或443完成,這在防火牆阻止非Web網絡連接的環境下是有益的。另外,Comet之類的技術以非標準化的方式實現了類似的雙向通信。

1.1 websocket特點

websocket的特點如下所示:

  • 提供全雙工通信;
  • 還可以在TCP之上啓用消息流;
  • WebSocket協議規範將ws(WebSocket)和wss(WebSocket Secure)定義爲兩個新的統一資源標識符(URI)方案,分別對應明文和加密連接。
  • WebSocket 的默認端口也選擇了 80 和 443,因爲現在互聯網上的防火牆屏蔽了絕大多數的端口,只對 HTTP 的 80、443 端口“放行”,所以 WebSocket 就可以“僞裝”成 HTTP 協議,比較容易地“穿透”防火牆,與服務器建立連接。
  • WebSocket 更側重於“實時通信”,而 HTTP/2 更側重於提高傳輸效率。

1.2 服務器支持框架

在服務器方面,網上都有不同對websocket支持的服務器:

1.3 websocket 幀結構

在這裏插入圖片描述

結束標誌位 + 操作碼 + 幀長度 + 掩碼

  • 第一位“FIN”:相當於 HTTP/2 裏的“END_STREAM”,表示數據發送完畢。一個消息可以拆成多個幀,接收方看到“FIN”後,就可以把前面的幀拼起來,組成完整的消息。
  • “FIN”後面的三個位是保留位,目前沒有任何意義,但必須是 0。
  • “Opcode”,操作碼:其實就是幀類型,比如 1 表示幀內容是純文本,2 表示幀內容是二進制數據,8 是關閉連接,9 和 10 分別是連接保活的 PING 和 PONG。
  • 掩碼標誌位“MASK”:表示幀內容是否使用異或操作(xor)做簡單的加密。目前的 WebSocket 標準規定,客戶端發送數據必須使用掩碼,而服務器發送則必須不使用掩碼。
  • Payload len”:表示幀內容的長度。它是另一種變長編碼,最少 7 位,最多是 7+64 位,也就是額外增加 8 個字節,所以一個 WebSocket 幀最大是 2^64。
  • Masking-key”:掩碼密鑰,它是由上面的標誌位“MASK”決定的,如果使用掩碼就是 4 個字節的隨機數,否則就不存在。

2 websocket握手過程

如下所示是筆者根據netty ws樣例進行瀏覽器瀏覽的一個用例,可以看到這個websocket鏈接可以分爲三個階段:

  1. 建立tcp鏈接;
  2. 客戶單採用http頭進行ws握手;
  3. 協議由http切換成ws傳輸數據;

在這裏插入圖片描述

2.1 客戶端的第一個GET

如下圖所示是客戶端websocket鏈接的第一個報文。

WebSocket 的握手是一個標準的 HTTP GET 請求,但要帶上兩個協議升級的專用頭字段:

  • “Connection: Upgrade”,表示要求協議“升級”;
  • “Upgrade: websocket”,表示要“升級”成 WebSocket 協議。

另外,爲了防止普通的 HTTP 消息被“意外”識別成 WebSocket,握手消息還增加了兩個額外的認證用頭字段(所謂的“挑戰”,Challenge):

  • Sec-WebSocket-Key:一個 Base64 編碼的 16 字節隨機數,作爲簡單的認證密鑰;
  • Sec-WebSocket-Version:協議的版本號,當前必須是 13。
    在這裏插入圖片描述

2.2 服務端響應 SwitchingProtocol

服務器收到 HTTP 請求報文,看到上面的四個字段,就知道這不是一個普通的 GET 請求,而是 WebSocket 的升級請求,於是就不走普通的 HTTP 處理流程,而是構造一個特殊的“101 Switching Protocols”響應報文,通知客戶端,接下來就不用 HTTP 了,全改用 WebSocket 協議通信。(有點像 TLS 的“Change Cipher Spec”)

WebSocket 的握手響應報文也是有特殊格式的,要用字段“Sec-WebSocket-Accept”驗證客戶端請求報文,同樣也是爲了防止誤連接。

具體的做法是把請求頭裏“Sec-WebSocket-Key”的值,加上一個專用的 UUID “258EAFA5-E914-47DA-95CA-C5AB0DC85B11”,再計算 SHA-1 摘要。

在這裏插入圖片描述

客戶端收到響應報文,就可以用同樣的算法,比對值是否相等,如果相等,就說明返回的報文確實是剛纔握手時連接的服務器,認證成功。

握手完成,後續傳輸的數據就不再是 HTTP 報文,而是 WebSocket 格式的二進制幀了。

2.3 客戶端ws報文

客戶端和服務端編碼則更好驗證了之前開頭的總結:

WebSocket 的幀頭就四個部分:“結束標誌位 + 操作碼 + 幀長度 + 掩碼”;

在這裏插入圖片描述

2.4 服務端ws回覆

在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章