1. 程式人生 > >websocket 和SSL淺析

websocket 和SSL淺析

1 WebSocket 原理

1.1 背景

WebSocket 是基於Http 協議的改進,Http 為無狀態協議,基於短連線,需要頻繁的發起請求,第二 Http 只能客戶端發起請求,服務端無法主動請求。

1.2 相同點

都是基於TCP的應用層協議。
都使用Request/Response模型進行連線的建立。
在連線的建立過程中對錯誤的處理方式相同,在這個階段WS可能返回和HTTP相同的返回碼。
都可以在網路中傳輸資料。

1.3 不同點

WS使用HTTP來建立連線,但是定義了一系列新的header域,這些域在HTTP中並不會使用。
WS的連線不能通過中間人來轉發,它必須是一個直接連線。
WS連線建立之後,通訊雙方都可以在任何時刻向另一方傳送資料。
WS連線建立之後,資料的傳輸使用幀來傳遞,不再需要Request訊息。
WS的資料幀有序。

WebSocket 分為握手和資料傳輸

1.4 握手

WebSocket 的握手基於http GET方法進行,

  1. 必須是有效的http request 格式
    HTTP request method 必須是GET,協議應不小於1.1 如: Get /chat HTTP/1.1
  2. 必須包括Upgrade 頭域,並且其值為“websocket”,表明http 協議升級為WebSocket.
  3. 必須包括”Connection” 頭域,並且其值為 “Upgrade”
  4. 必須包括”Sec-WebSocket-Key”頭域,其值採用base64編碼的隨機16位元組長的字元序列, 伺服器端根據該域來判斷client 確實是websocket請求而不是冒充的,如http。響應方式是,首先要獲取到請求頭中的Sec-WebSocket-Key的值,再把這一段GUID “258EAFA5-E914-47DA-95CA-C5AB0DC85B11”加到獲取到的Sec-WebSocket-Key的值的後面,然後拿這個字串做SHA-1 hash計算,然後再把得到的結果通過base64加密,就得到了返回給客戶端的Sec-WebSocket-Accept的http響應頭的值。
  5. 必須包括”Sec-webSocket-Version” 頭域,當前值必須是13.
    可能包括”Sec-WebSocket-Protocol”,表示client(應用程式)支援的協議列表,server選擇一個或者沒有可接受的協議響應之。
    可能包括”Sec-WebSocket-Extensions”, 協議擴充套件, 某類協議可能支援多個擴充套件,通過它可以實現協議增強
  6. 可能包括任意其他域,如cookie
客戶端的握手如下:
GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec
-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ== Origin: http://example.com Sec-WebSocket-Protocol: chat, superchat Sec-WebSocket-Version: 13 服務端的握手如下: HTTP/1.1 101 Switching Protocols Upgrade: websocket Connection: Upgrade Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo= Sec-WebSocket-Protocol: chat 客戶端和服務端都發送了握手,並且成功,資料傳輸即可開始。

1.5 資料傳輸

通過Http握手之後,如果是http 協議的話,tcp 連線會斷開,這裡在http 頭部指明瞭升級為 websocket, 所以tcp 連線不斷開。 WebSocket在握手後傳送資料並象下層TCP協議那樣由使用者自定義,還是需要遵循對應的應用協議規範。 WebSocket 資料傳輸以資料幀的形式傳輸。

資料幀的結構如下圖:

0                   1                   2                   3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-------+-+-------------+-------------------------------+
|F|R|R|R| opcode|M| Payload len |    Extended payload length    |
|I|S|S|S|  (4)  |A|     (7)     |             (16/64)           |
|N|V|V|V|       |S|             |   (if payload len==126/127)   |
| |1|2|3|       |K|             |                               |
+-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +
|     Extended payload length continued, if payload len == 127  |
+ - - - - - - - - - - - - - - - +-------------------------------+
|                               |Masking-key, if MASK set to 1  |
+-------------------------------+-------------------------------+
| Masking-key (continued)       |          Payload Data         |
+-------------------------------- - - - - - - - - - - - - - - - +
:                     Payload Data continued ...                :
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
|                     Payload Data continued ...                |
+---------------------------------------------------------------+
  1. FIN:1位,是否是訊息的結束幀(分片)
  2. RSV1, RSV2, RSV3: 分別都是1位, 預留,用於約定自定義協議。 如果雙方之間沒有約定自定義協議,那麼這幾位的值都必須為0,否則必須斷掉WebSocket連線;
  3. Opcode:4位操作碼,定義有效負載資料,如果收到了一個未知的操作碼,連線也必須斷掉,以下是定義的操作碼:

>
1. 0 表示連續訊息分片
2. 1 表示文字訊息分片
3. 2 表未二進位制訊息分片
4. 3-7 為將來的非控制訊息片斷保留的操作碼
5. 8 表示連線關閉
6. 9 表示心跳檢查的ping
7. A 表示心跳檢查的pong, 當收到一個Ping幀時,一個端點必須在響應中傳送一個Pong幀
8. B-F 為將來的控制訊息片斷的保留操作碼

  1. Mask: 定義傳輸的資料是否有加掩碼,如果設定為1,掩碼鍵必須放在masking-key區域,客戶端傳送給服務端的所有訊息,此位的值都是1;
  2. Payload length: 傳輸資料的長度,以位元組的形式表示:7位、7+16位、或者7+64位。如果這個值以位元組表示是0-125這個範圍,那這個值就表示傳輸資料的長度;如果這個值是126,則隨後的兩個位元組表示的是一個16進位制無符號數,用來表示傳輸資料的長度;如果這個值是127,則隨後的是8個位元組表示的一個64位無符合數,這個數用來表示傳輸資料的長度。多位元組長度的數量是以網路位元組的順序表示。負載資料的長度為擴充套件資料及應用資料之和,擴充套件資料的長度可能為0,因而此時負載資料的長度就為應用資料的長度。注意Payload length不包括Masking-key在內。
  3. Masking-key: 0或4個位元組,客戶端傳送給服務端的資料,都是通過內嵌的一個32位值作為掩碼的;掩碼鍵只有在掩碼位設定為1的時候存在。 資料Mask方法是,第 i byte 資料 = orig-data \^ (i % 4)

2 AndroidSync 框架

AndroidAsync 是一個基於nio的非同步socket ,http(客戶端伺服器端),websocket,socket.io庫,AndroidAsync 是一個底層的網路協議庫。AndroidAsync 適合用於一個未被封裝的Android的raw Socket, HTTP client/server, WebSocket, and Socket.IO。

>
特性

  1. 基於NIO,一個執行緒,回撥驅動,高效
  2. 所有的操作返回一個Future,而且可以取消
  3. All operations return a Future that can be cancelled
  4. Socket client + socket server
  5. HTTP client + server
  6. WebSocket client + server
  7. Socket.IO 客戶端

2.1 啟動websocket 服務

void startWebSocketService(){

        AsyncHttpServer server = new AsyncHttpServer();
        server.setErrorCallback(new CompletedCallback() {
            @Override
            public void onCompleted(Exception ex) {
            }
        });

        server.listen(AsyncServer.getDefault(), 5000);

        server.websocket("/ws", new AsyncHttpServer.WebSocketRequestCallback() {
            @Override
            public void onConnected(final WebSocket webSocket, AsyncHttpServerRequest request) {
                mServiceSocket = webSocket;

                //Use this to clean up any references to your websocket
                webSocket.setClosedCallback(new CompletedCallback() {
                    @Override
                    public void onCompleted(Exception ex) {
                        try {
                            if (ex != null) {
                            }
                        } finally {
                        }
                    }
                });

                webSocket.setStringCallback(new WebSocket.StringCallback() {
                    @Override
                    public void onStringAvailable(String s) {

                    }
                });
            }
        });
    }

2.2 客戶端發起連線

void startWebSocketClient(){
        AsyncHttpClient.getDefaultInstance().websocket(WSURL,  null, new AsyncHttpClient.WebSocketConnectCallback() {
            @Override
            public void onCompleted(Exception ex, WebSocket webSocket) {
                if (ex != null) {;
                    return;
                }

                mClientSocket = webSocket;
                webSocket.send("Hello Server");
                webSocket.setStringCallback(new WebSocket.StringCallback() {
                    public void onStringAvailable(String s) {

                    }
                });
            }
        });
    }

3 SSL

3.1 SSL加密

wss 建立在HTTPS 的基礎上,在握手的時候使用HTTS 建立連線。HTTPS是HTTP over SSL/TLS,HTTP是應用層協議,TCP是傳輸層協議,在應用層和傳輸層之間,增加了一個安全套接層SSL/TLS。
HTTPS 連線過程如下圖:

  1. 客戶端發起一個https的請求,把自身支援的一系列Cipher Suite(金鑰演算法套件,簡稱Cipher)傳送給服務端 ClientHello

  2. 服務端接收到客戶端所有的Cipher後與自身支援的對比,如果不支援則連線斷開,反之則會從中選出一種加密演算法和HASH演算法,以證書的形式返回給客戶端。ServerHello Certificate ServerHelloDone

  3. 客戶端收到服務端響應的證書後. client_key_exchange+change_cipher_spec+encrypted_handshake_message

    1. 第一步、校驗證書的是否有效。關於客戶端校驗證書的是否有效已經做了詳細的介紹,這裡就不贅述了。
    2. 第二步、生成隨機密碼。如果證書驗證通過,或者使用者接受了不授信的證書,此時瀏覽器會生成一串隨機密碼,然後用證書中的公鑰加密。
    3. 第三步、用最開始約定好的HASH方式,把握手訊息取HASH值,把用 隨機數密碼加密 “握手訊息+握手訊息HASH值(簽名)”和用公鑰加密的隨機密碼 一起傳送給服務端。把握手訊息做一個簽名,用於驗證握手訊息在傳輸過程中沒有被篡改過。
  4. 服務端拿到客戶端傳來的密文,用自己的私鑰來解密,獲取隨機密碼,再用隨機數密碼 解密 握手訊息與HASH值,並與傳過來的HASH值做對比確認是否一致。然後用隨機密碼加密一段握手訊息(握手訊息+握手訊息的HASH值 )給客戶端。(此時伺服器端已經獲取到了客戶端生成的隨機密碼了) 服務端用隨機密碼解密並計算握手訊息的HASH,如果與客戶端發來的HASH一致,此時握手過程結束。
    change_cipher_spec+encrypted_handshake_message

AndroidSync API
AndroidSync 對ssl 的支援如下:

        KeyManagerFactory kmf = KeyManagerFactory.getInstance("X509");
        KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());

        ks.load(getContext().getResources().openRawResource(R.raw.keystore), "storepass".toCharArray());
        kmf.init(ks, "storepass".toCharArray());

        TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
        KeyStore ts = KeyStore.getInstance(KeyStore.getDefaultType());
        ts.load(getContext().getResources().openRawResource(R.raw.keystore), "storepass".toCharArray());
        tmf.init(ts);

        SSLContext sslContext = SSLContext.getInstance("TLS");
        sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);

        AsyncHttpServer httpServer = new AsyncHttpServer();
        httpServer.listenSecure(8888, sslContext);
        httpServer.get("/", new HttpServerRequestCallback() {
            @Override
            public void onRequest(AsyncHttpServerRequest request, AsyncHttpServerResponse response) {
                response.send("hello");
            }
        });

        Thread.sleep(1000);

        AsyncHttpClient.getDefaultInstance().getSSLSocketMiddleware().setSSLContext(sslContext);
        AsyncHttpClient.getDefaultInstance().getSSLSocketMiddleware().setTrustManagers(tmf.getTrustManagers());
        AsyncHttpClient.getDefaultInstance().executeString(new AsyncHttpGet("https://localhost:8888/"), null).get();

3.2 自簽名證書驗證

ssl 連線需要證書,通常證書是CA機構釋出,保證權威性。但是也可以使用自簽名證書。如12306.根據我們車機的特點,可以採用自簽名證書。

public SSLSocketFactory get12306SSLSocketFactory() {
        try {
            BufferedInputStream bis = new BufferedInputStream(new ByteArrayInputStream(CER_12306.getBytes()));
            CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
            Certificate cert = certificateFactory.generateCertificate(bis);
            Log.d("https", cert.toString());

            KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
            keyStore.load(null);
            keyStore.setCertificateEntry("12306", cert);


            SSLContext sslContext = SSLContext.getInstance("TLS");
            TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
            trustManagerFactory.init(keyStore);
            sslContext.init(null, trustManagerFactory.getTrustManagers(), new SecureRandom());

            return sslContext.getSocketFactory();
        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }

    void httpConnect(){
        try {
            URL url;
            url = new URL("https://kyfw.12306.cn/otn/");
            HttpsURLConnection.setDefaultSSLSocketFactory(get12306SSLSocketFactory());
            HttpsURLConnection conn = (HttpsURLConnection)url.openConnection();
            conn.setDoOutput(true);
            conn.setDoInput(true);
            conn.connect();
            if(conn.getResponseCode() == HttpURLConnection.HTTP_OK){
                Log.e("https", "Https Certificate Success!");
                Message msg = Message.obtain();
                msg.what = HttpsActivity.HTTPS_SUCCES_12306;
                mViewHandler.sendMessage(msg);
            }
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

3.3 SSL 中間人攻擊

>
HTTPS ,是一種網路安全傳輸協議,利用 SSL/TLS 來對資料包進行加密,以提供對網路伺服器的身份認證,保護交換資料的隱私與完整性。 中間人攻擊, Man-in-the-middle attack ,縮寫: MITM ,是指攻擊者與通訊的兩端分別建立獨立的聯絡,並交換其所收到的資料,使通訊的兩端認為他們正在通過一個私密的連線與對方直接對話,但事實上整個會話都被攻擊者完全控制。
https 在理論上是可以抵禦 MITM ,但是由於開發過程中的編碼不規範,導致 https 可能存在 MITM 攻擊風險,攻擊者可以解密、篡改 https 資料。 0X02 https 漏洞 Android https 的開發過程中常見的安全缺陷:

1)在自定義實現 X509TrustManager 時, checkServerTrusted 中沒有檢查證書是否可信,導致通訊過程中可能存在中間人攻擊,造成敏感資料劫持危害。

2)在重寫 WebViewClient 的 onReceivedSslError 方法時,呼叫 proceed 忽略證書驗證錯誤資訊繼續載入頁面,導致通訊過程中可能存在中間人攻擊,造成敏感資料劫持危害。

3)在自定義實現 HostnameVerifier 時,沒有在 verify 中進行嚴格證書校驗,導致通訊過程中可能存在中間人攻擊,造成敏感資料劫持危害。

4)在 setHostnameVerifier 方法中使用 ALLOW_ALL_HOSTNAME_VERIFIER ,信任所有 Hostname ,導致通訊過程中可能存在中間人攻擊,造成敏感資料劫持危害。

相關推薦

websocket SSL淺析

1 WebSocket 原理 1.1 背景 WebSocket 是基於Http 協議的改進,Http 為無狀態協議,基於短連線,需要頻繁的發起請求,第二 Http 只能客戶端發起請求,服務端無法主動請求。 1.2 相同點 都是基於TCP的應用層協

如何讓服務端同時支援WebSocketSSL加密的WebSocket(即同時支援wswss)?

  自從HTML5出來以後,使用WebSocket通訊就變得火熱起來,基於WebSocket開發的手機APP和手機遊戲也越來越多。我的一些開發APP的朋友,開始使用WebSocket通訊,後來覺得通訊不夠安全,想要對通訊進行加密,於是自然而然地就想從ws升級到wss。在升級的過程中,就會存在舊的ws客戶端與新

Java多線程編程:Callable、FutureFutureTask淺析

創建線程 執行 過程 data- body javase 接下來 而後 定義 通過前面幾篇的學習,我們知道創建線程的方式有兩種,一種是實現Runnable接口,另一種是繼承Thread,但是這兩種方式都有個缺點,那就是在任務執行完成之後無法獲取返回結果,那如果我們想要獲取返

聊聊HTTPSSSL/TLS協議

常用 電信 hellip 以及 設有 可擴展 地址 玩意兒 winrar 要說清楚 HTTPS 協議的實現原理,至少需要如下幾個背景知識。 大致了解幾個基本術語(HTTPS、SSL、TLS)的含義 大致了解 HTTP 和 TCP 的關系(尤其是“短連接&

PAMSSL認證了解

linuxpamssl認證PAM認證PAM(Pluggable Authentication Modules)可插拔認證模塊是由Sun互聯網技術服務公司提出的一種用戶密碼認證機制。它通過一些動態鏈接庫和一套統一的API,將系統提供的服務和該服務的認證方式分開。PAM有四種模塊類型:auth (認證管理)

HTTP中請求響應淺析

cati odi 客戶端 9.png bubuko 連接 str tps size HTTP中的請求 HTTP中請求由三部分組成: HTTP中請求行:請求行分為三部分(請求方法+請求地址+協議和版本)例: POST/GET https://www.baidu.com/

93.Nginx配置:負載均衡SSL配置

Nginx配置:負載均衡和SSL配置一、負載均衡 負載均衡在服務端開發中算是一個比較重要的特性。因為Nginx除了作為常規的Web服務器外,還會被大規模的用於反向代理前端,因為Nginx的異步框架可以處理很大的並發請求,把這些並發請求hold住之後就可以分發給後臺服務端(backend servers,也叫做

【Qt Tips】QLineEdit內容過濾之setValidatorsetInputMask淺析

neo 淺析 utm bsp edit ips put nbsp ida 1、QValidator分析 2、InputMask格式 3、測試代碼和用例 項目路徑: GitHub: https://github.com/Qunero/NeoQtTestDe

nginxssl的安裝使用

cati CI 端口 安裝nginx efi 配置 安裝 org 啟動 最近想把網站加上ssl證書,只能在nginx上使用,就順便了解下nginx,我用的是centos6.5,開始 1.下載nginx及相關組件 切換到root用戶,進入存放下載文件的目錄 cd /usr/

第18章-使用WebSocketSTOMP實現消息功能

control rom rup mpm 空間 except 線路 如何 cto Spring 4.0為WebSocket通信提供了支持,包括: 發送和接收消息的低層級API; 發送和接收消息的高級API; 用來發送消息的模板; 支持SockJS,用來解決瀏覽器端、服務器

SSL Certificate Signed Using Weak Hashing Algorithm SSL Medium Strength Cipher Suites Supported的解決方案

ble 開始 tcp 哈希 tco sha1 ren 管理 例如 這兩天有個項目被掃描器報了幾個中危,都是SSL證書的問題。記錄一下解決方案吧。 第一個問題:SSL Certificate Signed Using Weak Hashing Algorithm 這裏的原因是

spring websocket socketjs實現單聊群聊,廣播的消息推送詳解

退出 rec oid -name 返回 classes sockets 們的 tomcat7.0 spring websocket 和socketjs實現單聊群聊,廣播的消息推送詳解 WebSocket簡單介紹   隨著互聯網的發展,傳統的HTTP協議已經很難滿足Web應用

HTTPSSSL並不意味著您擁有安全的網站

HTTPS和SSL並不意味著您擁有安全的網站 在大多數情況下,搜尋引擎優化社群首先將注意力轉移到小綠色鎖定,當時百度SEO專家釋出了一篇宣佈HTTPS作為排名訊號的帖子。幾乎所有的SEO都建議他們的HTTP客戶端為了排名目的而轉向HTTPS,但實際上,它從未(也絕不應該)關於排名。 那麼百度為什麼要談論排

websocketlayim快速構建即時聊天。

公司需要給網站接入聊天室功能,沒有辦法去網上找demo發現一款好的產品推薦給大家。 webim-plugin ,基於workerman和layim構建的web聊天擴充套件外掛,只需要配置下就能使用,快速方便。功能全面:單聊、群聊、群管理、群名片、建立好友分組、修改刪除好友分組、離線訊息、

prototype_proto_淺析

JS的原型分成兩類:隱式原型和顯示原型 顯示原型只有函式有,隱式原型所有物件都有 _proto_是實現繼承的原理, 通過_proto_指向實現繼承 1.預設情況 function person(name) { this.name = name; } var person1 =

Lua的rawsetrawget淺析

定義 raw:原始的,未加工的。 rawset/rawget:對“原始的”表進行直接的賦值/取值操作。 所以,raw方法就是忽略table對應的metatable,繞過metatable的行為約束,強制對原始表進

MapReduce簡介過程淺析

http putc 後臺 產生 collect map() shuf 具體步驟 大數據 預備知識:什麽是hadoop,HDFS? Hadoop是一個開源框架,它允許在整個集群使用簡單編程模型計算機的分布式環境存儲並處理大數據。它的目的是從單一的服務器到上千臺機器的擴展,每一

WebSocketsocket介紹

B/S結構的軟體專案中有時客戶端需要實時的獲得伺服器訊息,但預設HTTP協議只支援請求響應模式,這樣做可以簡化Web伺服器,減少伺服器的負擔,加快響應速度,因為伺服器不需要與客戶端長時間建立一個通訊連結,但不容易直接完成實時的訊息推送功能,如聊天室、後臺資訊提示、實時更新資料等功能,但通過p

websocket node.js 安裝配置

隨筆-82  文章-0  評論-3  Windows下Node.js+Express+WebSocket 安裝配置 Linux參考: Linux安裝Node.js  使用Express搭建Web伺服器    

jdbc連線mysql資料庫報時區錯誤SSL連線錯誤

錯誤1:時區錯誤 報錯資訊: com.mysql.cj.core.exceptions.InvalidConnectionAttributeException: The server time zone value '?й???????' is unrecognized or represe