如何讓服務端同時支援WebSocket和SSL加密的WebSocket(即同時支援ws和wss)?

zhuweisky發表於2017-11-17

  自從HTML5出來以後,使用WebSocket通訊就變得火熱起來,基於WebSocket開發的手機APP和手機遊戲也越來越多。我的一些開發APP的朋友,開始使用WebSocket通訊,後來覺得通訊不夠安全,想要對通訊進行加密,於是自然而然地就想從ws升級到wss。在升級的過程中,就會存在舊的ws客戶端與新的wss客戶端同時連線到同一個伺服器的情況。所以,如果同一個服務端,能同時支援ws和wss,那就太方便了。

一. 實現方案

  但是,要服務端同時支援ws與wss並不太容易,其難點主要在於:wss通道必須在TCP連線剛建立時(收發訊息前)就要先進行SSL加密,否則,後續的通訊將無法正常進行。如此一來,當同時存在ws和wss客戶端時,伺服器在尚未通訊之前就無法具體分辨哪個是ws哪個是wss。那怎麼辦了?我們的解決方案,是採用試探法,該方案已經在 ESFramework 通訊框架中實現。 

(1)由於wss通道必須在TCP連線剛建立時(收發訊息前)就要先進行SSL加密,否則,後續的通訊將無法正常進行。

(2)基於(1),在沒有收發任何訊息時,服務端就無法將wss客戶端與其它客戶端區分開來。

(3)為此採用的辦法是:對於任何剛建立的TCP連線,先都不加密它,等收到的第一個訊息來判斷其訊息的頭標誌。

(4)如果頭標誌不是ESFramework所規定的標誌,則表示這第一個訊息是密文,無法被解析,從而說明這個客戶端是wss。於是將該客戶端的ip放到cache中,並斷開該連線。

(5)wss客戶端會重新連上來,此時服務端從cache中發現已經存在目標ip,則判定其為wss客戶端,於是立即使用SSL加密該通道,之後,該wss客戶端就可以正常通訊了。

(6)由於wss 客戶端 IP在cache中的過期時間是 6秒左右,所以,如果一個客戶端IP剛登入了wss客戶端,那麼在同一個IP上登入第二個客戶端(任何客戶端型別),就需要相隔6秒之後。

   基於以上方案實現服務端後,我們接下來基於 ESFramework入門demo 來具體講解一下如何在實際應用中同時支援ws和wss。

二. 服務端實現

1. 數字證書

      為測試方便,我們可以使用 CertificateCreator 製作一個用於本地測試的數字證書。

      執行 CertificateCreator.exe, 然後輸入Common Name(比如Test)、密碼、儲存路徑(比如D:\server.pfx),我們就可以得到包含私鑰的證書server.pfx 。雙擊server.pfx ,即可安裝證書。 

2. 服務端引擎設定

       在服務端RapidServerEngine初始化之前,新增如下程式碼設定其 WssOptions 屬性:

        WssOptions wssOptions = new WssOptions( new X509Certificate2("D:\\server.pfx", "password") ,SslProtocols.Default ,false);
        rapidServerEngine.WssOptions = wssOptions;   

        設定完成後,啟動服務端。 

三. 客戶端實現

1. 信任測試用的數字證書      

        由於上述生成的數字證書僅僅是用於測試的,而是不被正式認可的,所以,需要在瀏覽器設定中,將目標數字證書加入到信任列表。

        比如,在360瀏覽器中,可如下設定:

          

        在FireFox中,設定如下:

         

          將伺服器的地址(https://127.0.0.1:4530)新增到例外中。  

2. 客戶端引擎設定

        開啟入門demo的Web端原始碼中的index.js檔案,找到engine的Initialize方法,將 useWss 引數由false修改為true。

        然後將Web端的 index.html 檔案拖入瀏覽器中執行即可。 

四. 執行效果

       登入一個wss客戶端,一個ws客戶端和一個.NET客戶端,服務端的UI顯示如下:

       

        下載 Demo原始碼

 

 

       

相關文章