TCP和TLS/SSL會話細節

 

TCP數據段格式說明
TCP創建鏈接和斷開鏈接細節
Https如何保證通訊安全
一次Https網絡請求通訊細節
網絡數據包分析工具wireshark的使用
問題:
SYN、ACK、FIN具體含義是什麼?
TCP創建鏈接超時的表現?html

爲何須要證書來下發服務端公鑰?
客戶端是如何驗證證書合法性的?
對稱祕鑰是如何協商出來的?
爲何不直接讓客戶端本身生成一個祕鑰發送給服務端使用?
TLS如何避免重放攻擊?git

TCP數據包格式說明
TCP數據段分爲首部+數據兩部分。
首部又分爲固定首部和可選項首部。
經過對TCP數據包格式的分析,就是了解TCP協議定義的過程。
算法

來源鏈接端口(16比特位)-辨識發送鏈接端口
目的鏈接端口(16比特位)-辨識接收鏈接端口
序列號(seq,32比特位)-TCP數據包標識。
無懼傳輸時的亂序或丟包
創建鏈接時發送和接收方第一次數據段的seq均爲隨機生成(TCP序號預測攻擊),以後是上次序列號加1
發送數據時seq爲上一次發送的數據長度加1,若是數據長度爲0則seq不變
確認號(ack,32比特位)-表示接收方指望下次收到的數據包的序列號的值,也是當前收到的數據的字節長度加1
數據偏移(4比特位)-以4字節爲單位計算出的數據段開始地址的偏移值,例1111 -> 15 -> 60字節
保留位(3比特位)-需置爲0
標誌符(9比特位)
NS:Nonce Sum 隨機和,
CWR:Congestion Window Reduced 擁塞窗口減小標誌被髮送主機設置,用來代表它接收到了設置ECE標誌的TCP包。擁塞窗口是被TCP維護的一個內部變量,用來管理髮送窗口大小
ECE:ECN-Echo(顯式擁塞通知回顯) ECN響應標誌被用來在TCP3次握手時代表一個TCP端是具有ECN功能的,而且代表接收到的TCP包的IP頭部的ECN被設置爲11 NS/CWR/ECE三個標誌組合實現估計網絡擁塞狀況的功能
URG:爲1表示高優先級數據包,緊急指針字段有效
ACK:爲1表示確認號字段有效
PSH:爲1表示是帶有PUSH標誌的數據,指示接收方應該儘快將這個報文段交給應用層而不用等待緩衝區裝滿
RST:爲1表示出現嚴重差錯,可能須要從新建立TCP鏈接,還能夠用於拒絕分發的報文段和拒絕鏈接請求
SYN:爲1表示這是鏈接請求或是鏈接接受請求,用於建立鏈接和使順序號同步
FIN:爲1表示發送方沒有數據要傳輸了,要求釋放鏈接
窗口(WIN 16比特位)-表示從確認號開始,本報文的接收方能夠接收的字節數,即接收窗口大小,用於流量控制
校驗和(Checksum 16比特位) -對整個TCP報文段,包括TCP首部和TCP數據,計算出來的16位值,這是一個強制字段。校驗方式爲:將TCP報文段的頭部和數據部分的和計算出來,再對其求反碼
緊急指針(16比特位)-本報文段中的緊急數據的最後一個字節的序號
選項字段 -最多40字節,每一個選項的開始是1字節的kind字段,說明選項的類型。下面具體說明支持的選項字段類型
0:(1字節)選項表結束
1:無操做(1字節)用於選項字段之間的字節邊界對齊和分割不一樣的選項數據
2:最大報文長度(4字節,Maximum segment size,MSS) -在握手階段告知接收方,發送方支持的最大報文數據段的長度,以太網通常爲1460。只能出如今同步報文段中,不然將被忽略。一般將MSS設置爲MTU-40字節(Maximum Transmission Unit 最大傳輸單元),這樣攜帶TCP報文段的IP數據報的長度就不會超過MTU,從而避免本機發生IP分片。
3:窗口擴大因子(3字節,wscale)-取值0-14,用來把TCP的窗口的值左移的位數。只能出如今同步報文中,不然將被忽略。這是由於如今的TCP接收數據緩衝區(接收窗口)的長度一般大於65535字節
4:sackOK -發送端支持並贊成使用SACK(Selective Acknowledgements,選擇確認)選項
5:SACK實際工做的選項,存放丟包的邊界信息,最多存放4個包的邊界信息。例如123,丟了2,那麼SACK存放的就是2號包的開始和結束的字節序列號
8:時間戳(10字節,TCP Timestamps Option,TSopt)
發送端的時間戳(Timestamp Value field, TSval,4字節)
時間戳回顯應答(Timestamp Echo Reply field,TSecr,4字節)
時間戳的功能有兩個:
用來計算往返時間RTT(Round-Trip Time),發送方在收到確認報文後,能夠準確計算出RTT。
防止迴繞的序列號,經過時間戳能夠判斷出相同序列號的數據報,哪一個是最近發送的,哪一個是之前發送的。
滑動窗口
簡單一句話就是接收方能夠動態控制發送方下次發送的TCP包數據段的大小。
當接收方處理數據較慢時,就能夠經過WIN字段,在ACK包中告知發送方:「之後的數據段少發一些,我處理不過來了。」
在極端狀況下,接收方連1字節的數據也不能處理了,那麼WIN字段就設置爲0,發送方就會中止發送後續的TCP包。
那麼,當接收方緩過氣來,能夠處理更多數據時,發送方是怎麼知道的呢?答案是Zero Window Probe(零窗口探針)技術。
發送方會在必定時間間隔內重複發送ZWP包,這時接收方就有機會告知發送方最新的窗口大小。
又有極端狀況,接收方一直返回WIN爲0,那麼發送方在發送必定次數的ZWP後,就會發送RST包來斷開鏈接(不一樣的系統有不一樣的實現)。瀏覽器

另一種極端狀況,接收方返回的WIN值特別小,相對於TCP的首部來講,發送較少的數據時一種浪費。這個時候接收方就會使用David D Clark’s 方案。接收方直接返回WIN爲0,知道接收方有足夠的能力處理新數據時再把WIN打開。緩存

若是是因爲發送方發送的數據特別少引發的,那麼發送方就會使用Nagle’s algorithm。將多個小的數據包緩存起來,直到知足發送條件。安全

ECE和CWR
當兩個支持ECN的TCP端進行TCP鏈接時,對於支持ECN的TCP端來講,SYN包的ECE和CWR標誌都被設置了。SYN-ACK只設置ECE標誌。bash

一個支持ECN的TCP主機在支持ECN的TCP鏈接上發送設置了IP頭部爲10或者01的TCP包。支持ECN的路由器在經歷擁塞時設置IP頭部的ECN域爲11。當一個TCP接收端發送針對收到的一個設置ECN位爲11的TCP包的響應時,它設置TCP包頭中的ECE,而且在接下來的ACK中也作一樣設置。服務器

當發送主機接收到設置了ECE標誌的ACK時,它就像感知到包丟失同樣,開始減小發送窗口,運行慢啓動過程和擁塞避免算法。在下一個數據包中,發送者設置CWR標誌。在接收到新的設置CWR標誌的包時,接受者中止在接下來的ACK中設置ECE標誌。網絡

超時重傳
創建鏈接時:app

若是發送方在發送一個SYN包後,在超時時間內沒有收到確認包,則發送方會從新發送,稱爲超時重發。
默認Linux重試次數爲5次,重試時間間隔由1s開始每次翻倍,即1s,2s,4s,8s,16s。若是通過1+2+4+8+16+32=63s後,仍沒有收到確認包,則發送方認爲接收方已掉線,會主動斷開當前鏈接。

數據傳輸時:

爲了網絡總體的穩定,須要動態的根據往返時間設置數據包的超時時間。這裏就不展開說具體算法過程了。
RTO(Retransmission Timeout)重傳超時時間
RTT(Round-Trip Time)往返時間

擁塞控制
慢啓動
擁塞避免
快速重傳
快速恢復

三次握手 和 四次揮手
三次握手

這是簡單的三次握手流程示意圖,三次握手意思是須要在發送方和接收方之間傳遞三個數據包。經過設置不一樣的標識位,來告知對方當前數據包的意圖。

第一次:C發送一個數據包P1給S,並將標識位的SYN置爲1,代表「我要和你創建鏈接」。

第二次:S若是能夠接受C的請求,會給C回發一個數據包P2,並將標識位SYN置爲1,代表「我贊成和你創建鏈接」。同時將ACK位置爲1,代表「確認號ack」字段有效,其值爲P1數據包序列號+1。

第三次:C接到P2後,會再次向S發送數據包P3,將ACK爲置爲1,其值爲P2數據包的序列號+1,代表「我知道了你贊成了」。

至此,鏈接就被創建完成了,雙方就能夠任意發送數據了。

可是,在三次握手過程當中,除了要協商鏈接的創建,還有其餘通信參數的設置。下面以一個真實請求在三次握手過程當中發生的數據交換做說明:

第一次:

第二次:

第三次:

四次揮手

這是TCP鏈接斷開時四次揮手的示意圖。劃重點:

每一側的鏈接都單獨的被終止。
主動終止鏈接的一方在接收到ACK後,不能再發送數據,但能夠接收數據,也就是半雙工狀態。
首先終止鏈接的一方,在給對方響應了ACK後,就會等待2*MSL(Max Segment Lifetime 報文最大生存時間)時間,而後關閉鏈接。RFC793定義了MSL爲2分鐘,Linux設置成了30s。
四次揮手也能夠經過三次握手實現,即主機A發出FIN,主機B回覆FIN&ACK,主機A回覆ACK。
下面是三次握手實現的鏈接斷開的報文傳輸細節:

第一次:

 

第二次:

第三次:

 

Https如何保證通訊安全
簡介
Https 超文本傳輸安全協議(Hypertext Transfer Protocol Secure),1994年由網景公司提出,Https經由Http進行通訊,但利用SSL/TLS來加密數據,即在Http協議與TCP協議之間添加SSL/TLS層。

安全防禦:

身份認證,防止中間人攻擊
消息加密,防止被竊聽
消息校驗,防止被篡改
安全前提:
系統或瀏覽器正確的實現了Https並安裝了正確的證書頒發機構

安全通訊流程
對稱加密
算法公開(AES)
一個祕鑰,祕鑰不公開
加解密速度快

非對稱加密
算法公開(RSA)
兩個祕鑰,公鑰公開,私鑰不公開
公鑰加密的數據,私鑰能夠解密。私鑰加密的數據,公鑰能夠解密
加解密速度慢

非對稱加密算法除了能夠直接將隱私數據加密外,還能夠實現對非隱私數據的防篡改校驗功能,也就是數字簽名。

Hash/散列/摘要算法
以任意長度的數據爲輸入,輸出固定長度的數字「指紋」。
MAC,消息認證碼,是帶祕鑰的Hash算法,即在對數據計算散列值時將祕鑰和數據同時做爲輸入,並採用二次散列迭代的方式。

Alice和Bob
在沒有SSL/TLS的世界裏,Alice和Bob的通信是這樣的。

Alice(i love you)–明文(i love you)–>Bob(i love you)

一些壞人能夠在明文的傳輸過程當中,對數據進行更改。

Alice(i love you)–>壞人(i hate you)–>Bob(i hate you)

Bob(i still love you )–>壞人(i hate you too)–>Alice(i hate you too)

當兩人見面後,發現對方誤會了本身,就想到這個世界仍是有壞人,而後雙方約定將通訊內容加密後再發送給對方。約定的加密算法爲AES,祕鑰爲「Alice/Bob」。
加密後就會出現兩種狀況:
Alice(i love you)–加密(123abc)–>壞人(123abc)–>Bob(123abc)–>解密(i love you)

Alice(i love you)–加密(123abc)–>壞人(!!!)–>Bob(!!!)–>解密(???)
單純使用對稱加密會有兩個問題:

壞人雖然不能竊聽內容,可是仍能篡改。
對稱加密的祕鑰只能Alice和Bob兩我的知道,若是想再和更多的人加密通訊的話,就無能爲力了。
Alice和Bob必須在通訊以前就約定好祕鑰(在互聯網世界中辦不到),中途沒法更新。
因此,咱們要解決這些問題,須要作到:

爲了過濾掉被篡改的數據,通訊過程須要有內容校驗機制
爲了能夠和無限多人通訊,須要能動態生成和更新祕鑰
Alice和Bob很是聰明,他們想到了非對稱加密算法RSA,Bob拿着私鑰,而後把公鑰給Alice,當Alice想要和Bob通訊時,利用手中的公鑰將對稱加密算法的祕鑰加密後發送給Bob,Bob拿着本身的私鑰將對稱加密的祕鑰解密後,雙方就能夠繼續用對稱加密算法將數據加密後通訊了。固然,其餘人也能夠拿到Bob的公鑰,與Bob通訊。

Alice(我想和你說話,給我公鑰)------->Bob(我想和你說話,給我公鑰)
Bob(給你公鑰(Pubkey)) --------->Alice(拿到公鑰PubKey)
Alice(祕鑰:123)–>公鑰PubKey加密(321)–>Bob(321)–>私鑰解密(123)

Alice(i love you)–>祕鑰123加密(123abc+摘要簽名)---->Bob(123abc+摘要簽名)–>正確性驗證–>祕鑰123解密(i love you)

上述第二個過程是無懈可擊的,可是第一個過程當中,若是存在壞人的話,就變成下面的情形

Bob(給你公鑰(PubKey))---->壞人(PubKey換成本身的PubKey1)--------->Alice(拿到公鑰PubKey1)
Alice(祕鑰:123)–>公鑰PubKey1加密(abc)–>壞人(abc),本身的私鑰解密123,再用PubKey加密321–>Bob(321)–>私鑰解密(123)

完犢子了,對稱加密的祕鑰被壞人竊取了,通訊數據又至關於裸奔了。其中核心問題就是:

接收方沒法肯定公鑰的合法性
那若是把公鑰事先告知Alice能夠麼?也就是內置在系統中。理論上是沒問題的,但當Alice須要和更多的人通訊時,她須要記住不少不少的公鑰,這是不可行的。

因此Alice和Bob須要商量出一套方案,能保證公鑰在網絡上安全的傳輸,若是受到篡改,接收方能感知到。這時,他們想到數字簽名的方式。

Bob(給你公鑰+簽名(摘要的私鑰加密))------>Alice(公鑰+簽名,對簽名解密,並再次計算摘要,而後比對)

上述方式能夠作到防篡改麼?能夠,可是作不到防替換。中間人能夠把簽名連同公鑰所有換成本身的。

接下來就到了數字簽名證書出場的時刻了。

Bob找到了一個很是權威的機構,「人民政府」。
Bob向「人民政府」證實「我是真Bob」,並提供本身的公鑰。
「人民政府」根據Bob的信息和公鑰頒發給Bob一個證書文件.cer,裏面寫了頒發機構的信息、Bob的信息和公鑰、摘要算法以及最重要的頒發機構的簽名。

公鑰下發過程變成了數字證書下發過程。

同時,Alice也是很是相信「人民政府」的,只要是「人民政府」簽名的證書,Alice就認爲證書上面的公鑰就是Bob的。

可是,Alice並不能無腦的相信,她須要判斷了兩點:

接收到的證書是不是」人民政府「簽發的。
證書上面的信息是否被篡改。
那麼具體的判斷流程是怎樣的呢?

因爲Alice信任」人民政府「這個機構,因此Alice能夠內置一份」人民政府「自簽名的證書,上面有」人民政府「生成的公私鑰中的公鑰,私鑰由」人民政府「本身保管。
在下發證書過程當中,Alice拿到Bob發過來的由」人民政府「私鑰簽名過得證書cert0。
Alice首先根據cert0上的證書頒發機構信息判斷本身是否信任這個機構頒發的證書,cert0是由」人民政府「簽發的,而Alice是信任」人民政府「的,因此Alice信任cert0。
Alice經過查找內置的」人民政府「的自簽名證書拿到」人民政府「的公鑰
用此公鑰驗證cert0上的信息是否被篡改
問題:Bob的公鑰不是由」人民政府「簽發的,而是由其下屬的」地方政府「簽發的。而Alice只有」人民政府「的自簽名政府,如何判斷證書合法性呢?

答:在證書下發過程當中,實際是下發的一個證書鏈,相似於」Bob的證書「–>「地方政府的證書」–>」人民政府的證書「,Alice能夠逐級查找,直到根證書。

證書內容
Https證書格式遵循的是X.509標準。X.509是ITU-T標準化部門基於他們以前的ASN.1定義的一套證書標準。

在瀏覽器中隨便下載一個證書,經過如下命令獲取到其文本格式。

openssl x509 -in *.xxx.com.cer -inform der -text -noout >> cer.txt 
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            09:3e:8a:aa:5a:f8:14:de:9d:d9:4d:28:2e:97:a8:16
        Signature Algorithm: sha256WithRSAEncryption
        Issuer: C=US, O=DigiCert Inc, OU=www.digicert.com, CN=GeoTrust RSA CA 2018  //頒發者信息
        Validity
            Not Before: Aug 22 00:00:00 2018 GMT
            Not After : Nov 12 12:00:00 2020 GMT
        Subject: C=CN, ST=\xE5\x8C\x97\xE4\xBA\xAC, L=\xE5\x8C\x97\xE4\xBA\xAC, 
O=Beijing Qfpay Technology Co., ltd., CN=*.qfpay.com //公鑰主題信息,公鑰全部者的信息
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (2048 bit)
                Modulus:
                    00:e6:c0:8b:f0:12:1e:f0:92:9c:17:7d:7e:d5:69:
                    47:fc:dd:0b:51:5a:0e:79:df:b1:0e:b4:d6:7d:d0:
                    5a:bc:f9:93:f6:3c:e3:40:a8:66:9f:d0:ae:3c:e1:
                    f8:9a:55:a2:84:0e:9c:1d:65:f9:d2:63:51:48:b2:
                    88:a5:09:a6:be:92:80:f8:3b:eb:b8:78:1b:35:58:
                    47:ac:eb:47:cd:3d:7f:36:74:30:7a:01:86:48:96:
                    b3:7b:14:82:b6:63:0b:b6:43:20:98:3f:07:9d:1a:
                    56:76:25:cf:cd:d5:49:fd:6e:dc:86:f0:7f:15:f3:
                    7d:58:98:75:a5:7f:f9:ab:b2:c4:ec:fc:30:bd:75:
                    27:b3:0e:72:3d:44:d1:04:42:52:65:9b:3e:53:9b:
                    a5:c2:eb:ac:c5:01:b6:1d:0d:2f:75:79:7d:98:d4:
                    2b:b6:c0:28:ea:c7:dc:14:04:b6:4d:a3:dc:01:2c:
                    f0:14:13:b9:d2:29:31:00:37:af:17:d6:82:a6:f9:
                    57:9e:4c:2f:27:27:08:50:16:e3:ca:fa:58:32:c7:
                    f5:04:43:b4:5d:0e:97:81:e9:c3:01:36:f9:b7:c8:
                    14:ec:98:27:e9:31:86:ab:f5:c4:ff:50:aa:c4:df:
                    cc:6e:7d:1c:5a:fa:b8:47:c9:fa:78:b4:de:6d:15:
                    8d:27
                Exponent: 65537 (0x10001)
        X509v3 extensions:
            X509v3 Authority Key Identifier: //受權祕鑰標識符
                keyid:90:58:FF:B0:9C:75:A8:51:54:77:B1:ED:F2:A3:43:16:38:9E:6C:C5

            X509v3 Subject Key Identifier: //主題祕鑰標識符
                EC:99:74:D5:FF:C6:1B:4F:FB:39:88:8C:E2:C1:7B:8D:90:59:AB:1F
            X509v3 Subject Alternative Name: 
                DNS:*.xxx.com, DNS:xxx.com
            X509v3 Key Usage: critical
                Digital Signature, Key Encipherment
            X509v3 Extended Key Usage: 
                TLS Web Server Authentication, TLS Web Client Authentication
            X509v3 CRL Distribution Points: 

                Full Name:
                  URI:http://cdp1.digicert.com/GeoTrustRSACA2018.crl

            X509v3 Certificate Policies: 
                Policy: 2.16.840.1.114412.1.1
                  CPS: https://www.digicert.com/CPS
                Policy: 2.23.140.1.2.2

            Authority Information Access: 
                OCSP - URI:http://ocsp1.digicert.com
                CA Issuers - URI:http://cacerts.geotrust.com/GeoTrustRSACA2018.crt

    Signature Algorithm: sha256WithRSAEncryption
         07:8d:b9:34:62:e8:4b:83:00:af:ab:38:d4:b1:24:12:a4:37:
         5e:8f:e7:ff:d9:96:48:ae:72:6f:d2:0b:41:6a:55:92:2a:06:
         39:86:a9:78:18:cd:0d:5f:33:fa:22:81:50:b7:67:2f:dc:a1:
         b4:ee:0f:6c:f8:73:87:0d:65:e7:19:9a:55:07:49:a4:2d:09:
         11:8b:5f:1c:c1:46:ce:94:22:fa:b0:1b:88:f0:f0:6f:63:11:
         e4:56:f4:51:3c:12:90:db:44:63:8b:fd:17:d2:e5:7a:66:5e:
         f5:d8:90:70:5c:d6:c2:74:d9:74:b3:75:ce:83:e3:db:57:bb:
         b6:3a:81:e7:ca:7a:48:82:6c:0b:01:a8:ed:a2:8e:d0:b0:ed:
         25:15:a2:2a:7f:6f:a5:6d:da:5a:ac:91:f4:dc:23:d8:9f:9d:
         d3:0a:f4:c7:8f:b0:c2:18:54:97:f5:00:30:36:65:e1:aa:25:
         9c:f1:b8:77:d6:7d:33:79:39:0e:41:86:1d:79:47:0e:34:cc:
         fd:e8:63:83:9d:f5:86:d6:e2:0c:fa:58:d5:d2:81:c1:92:da:
         e7:41:45:bc:a0:91:d5:40:6e:c8:22:76:69:e4:67:9a:d4:03:
         ca:8d:28:d5:ca:98:09:e0:d6:dd:ae:c2:6f:08:82:1b:89:79:
         14:d6:ca:b7

 

SSL/TLS握手細節

SSL/TLS報文格式

SSL協議屬於分層協議,一個SSL報文能夠包含多個記錄層,每一個記錄層分爲兩部分:頭部 + 協議數據。

Content Type:協議類型
Version:TLS版本
Length:報文長度
協議數據,不一樣的協議包含數據字段不一樣
報文支持的協議類型
Handshake Protocol
握手協議是最主要的協議,負責協商會話的安全屬性。按照不一樣的功能區分爲不一樣握手類型。

 1 enum {
 2           hello_request(0), client_hello(1), server_hello(2),
 3           certificate(11), server_key_exchange (12),
 4           certificate_request(13), server_hello_done(14),
 5           certificate_verify(15), client_key_exchange(16),
 6           finished(20), (255)
 7       } HandshakeType;
 8       
 9 struct {
10     HandshakeType msg_type;    /* handshake type */
11     uint24 length;             /* bytes in message */
12     select (HandshakeType) {
13         case hello_request:       HelloRequest;
14         case client_hello:        ClientHello;
15         case server_hello:        ServerHello;
16         case certificate:         Certificate;
17         case server_key_exchange: ServerKeyExchange;
18         case certificate_request: CertificateRequest;
19         case server_hello_done:   ServerHelloDone;
20         case certificate_verify:  CertificateVerify;
21         case client_key_exchange: ClientKeyExchange;
22         case finished:            Finished;
23     } body;
24 } Handshake;

 

每種握手協議類型,也都包含一些通用字段,如
HandshakeType
Version
Length

下面具體說明每種握手類型的做用:

Hello Request

」你好,請求「,該類型的握手協議做爲一個簡單的通知,由服務端發送,告知客戶端從新開始協商過程。做爲響應,客戶端應該在方便時發送ClientHello消息。
若是客戶端不但願從新協商會話,能夠選擇忽略此消息,或者返回一個no_renegotitation消息。
若是服務端發送HelloRequest後沒有收到ClientHello做爲響應,它可能會經過致命警報關閉鏈接。

Client Hello
」你好,我是客戶端「,該類型的消息用於首次鏈接服務器時,或響應服務端發送的HelloRequest,或主動發送,以便從新協商鏈接中的安全參數。

Random 由安全隨機數生成器生成的28字節隨機數,用於對稱祕鑰計算

Session ID 會話標識,可變長,用於會話恢復時重用其安全參數

Cipher Suites 加密算法套件,客戶端提供支持的密碼算法套件列表,按照客戶端的偏好順序排列,通常由四個算法組成,格式爲祕鑰交換算法+身份認證算法+批量加密算法+摘要算法

例:Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 (0xc02c)

ECDHE 祕鑰交換算法,因爲對稱祕鑰並非客戶端直接生成發送給服務端的,而是雙方又各自生成了一對"公私鑰",而後互相交換「公鑰」,這裏生成「公私鑰」的算法就是ECDHE
ECDSA 身份認證算法,用於加密握手消息,確認未被篡改
AES_256_GCM 批量加密算法,用於應用數據加密,它還包括祕鑰大小及顯示和隱式初始化向量的長度
SHA384 散列算法,用於計算主祕鑰和建立會話消息摘要

Compression Methods 壓縮算法列表

這四個屬於固定字段,若是還須要協商其餘內容,能夠經過下面的擴展字段。

renegotiation_info 從新協商信息,
signature_algorithms 簽名算法,列出客戶端支持的哈希和簽名算法,用於後續消息簽名時的參考。
server_name 服務器域名,用於解決一臺機器部署多個不一樣域名的站點,而引發證書衝突的狀況。
aplication_layer_negotiation 用來肯定後續的應用層協議,例http/1.1 spdy h2

Server Hello
」你好,我是服務端「,該類型的消息用於響應ClientHello消息。若是服務器找到一組能夠接受的算法套件時,則回覆此消息,不然響應握手失敗的警報。

Random 由服務端獨立生成的隨機數,28字節,用於對稱祕鑰的計算。

Session ID 當前的會話標識,若是ClientHello的參數SessionID不爲空,則服務器將在其會話告訴緩存中查找匹配項,找到而且願意是定指定的會話狀態創建鏈接,則服務器使用與客戶端提供的SessionID做爲響應,而後恢復會話並進入Finished消息流程。不然將從新生成該值以標識新會話。若是SessionID爲空代表服務端不緩存此會話,沒法恢復。

Cipher Suite 服務端從ClientHello.cipher_suites列表中選擇的單個密碼套件。若是是恢復會話,此字段爲正在恢復的會話狀態的值。

例:Cipher Suite: TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (0xc030)
ECDHE 橢圓曲線離散對數算法
RSA 非對稱加密算法
AES_256_GCM 高級加密算法,對稱加密,32字節的祕鑰 GCM爲加密模式
SHA384 安全散列算法

Compress Method 服務端從ClientHello.CompressionMethods列表中選擇的壓縮算法

Server Hello消息也能夠包含擴展,可是這些擴展必須在ClientHello中有相同的擴展類型,服務端不能擅自添加。若是客戶端在ServerHello中收到它未在ClientHello請求中關聯的擴展類型,客戶端必須使用unsupported_extension致命警告來終止握手。

Certificate
」服務器證書「,只要商定的祕鑰交換方法使用證書進行身份驗證,則服務端必須發送該證書消息。該消息緊跟在Server Hello消息後,用於向客戶端下發證書。
何時服務端不須要下發證書呢?就是在祕鑰協商過程當中使用DH_anon(Diffie-Hellman ANON)匿名Diffie-Hellman算法,即不配合其餘身份驗證算法,而單獨只讀使用DH算法,這樣沒法保證數據被」篡改「。

 

Certificates 證書鏈,服務端的證書必須放在第一位,之後的證書必須直接證實其前面的證書。
證書限制

證書類型必須是X.509v3,除非另行協商。
證書必須適用於協商密碼套件的祕鑰交換算法和任何協商擴展。
若是客戶端提供了」signature_algorithms「擴展,那麼服務端提供的全部證書必須由該擴展中出現的散列/簽名算法進行簽名。
Server Key Exchange
」服務器祕鑰交換「,用於發送服務端的預主祕鑰。此消息在Certificates消息後當即發送。
當且僅當與祕鑰交換算法相關聯的證書類型不能爲客戶端提供足夠的信息來交換預主祕鑰時,纔會發送服務器祕鑰交換信息。

該消息主要描述了使用協商的祕鑰交換算法後,服務端計算出來的公開祕鑰。
本示例中使用的是ECDHE算法。其原理簡單理解以下所示:

服務端生成隨機整數a,做爲私鑰
計算出A = f1(a),其中a爲私鑰,A爲公鑰,並將A發送給客戶端
客戶端重複相同的步驟,先生成隨機整數b,計算 B = f1(b),並將B發送給服務端
客戶端持有A和b,服務端持有a和B
服務端和客戶端計算出相同的預主祕鑰 K = f2(a, B) = f2(b, A)
以後再根據預主祕鑰和兩個隨機數計算出主祕鑰
上述計算過程由ECDHE提供
服務端爲了證實此消息是真實可靠的,須要用本身證書私鑰和ClientHello提供的擴展signature_algorithms裏選擇合適摘要和簽名算法對參數進行簽名。

Certificate Request 可選
」要求證書「,若是服務端須要客戶端提供證書以驗證客戶端身份,則使用此消息。消息格式與服務端下發給客戶端的證書消息格式相同。

Server Hello Done
「服務器Hello完成」,表示服務端已經把支持祕鑰交換的消息發送完成。發送此消息後,服務端等待客戶端響應。客戶端應該檢查服務器是否提供了有效的證書(若是須要),並檢查服務端Hello消息參數是否可接受。

Client Certificate
「客戶端證書」,用於將客戶端證書發送給服務端。

這是客戶端在收到ServerHelloDone消息後能夠發送的第一條消息。僅當服務器請求證書時纔會發送此消息。若是沒有合適的證書,客戶端必須發送不包含證書的證書消息。也就是說,certificate_list結構的長度爲零。若是客戶端沒有發送任何證書,服務器能夠自行決定是否在沒有客戶端身份驗證的狀況下繼續握手,或者使用致命的handshake_failure警報進行響應。此外,若是證書鏈的某些方面是不可接受的(例如,它沒有由已知的,可信的CA簽名),服務器能夠自行決定是繼續握手(考慮客戶端未經身份驗證)仍是發送致命警報。

Client Key Exchange
「客戶端祕鑰交換」,用於發送客戶端計算的預主祕鑰。該消息是在客戶端收到ServerHelloDone消息後發送的第一條消息。或者是跟在Client Certificate消息後發送。

 

這個消息內容比較簡單,就是用服務端證書公鑰加密的預主祕鑰。

Certificate Verify
「證書驗證」,此消息用於客戶端證書的顯示驗證。發送這個消息的前提有兩個:

服務端請求了客戶端證書
客戶端發送了非0長的證書
此時,客戶端須要證實本身擁有該證書,須要用本身的私鑰簽名一段數據發送給服務端作驗證。
簽名的數據爲:此消息以前的全部接收和發送過的握手消息。

Finished
「協商完成」,此消息是第一個使用上述握手過程當中協商的算法和祕鑰來加密的消息。接收方必須驗證內容是否正確。
該消息在Change Cipher Spec消息以後被髮送,以驗證密鑰交換和身份驗證過程是否成功。
發送的數據爲:PRF(master_secret, finished_label, Hash(handshake_messages))
finished_label爲「client finished」/「server finished」
handshake_messages包含除去Hello Request消息以外的以前全部發送和接收的握手消息。

Change Cipher Spec Protocol
更改密碼規範協議,該協議在TSL1.3被移除。

Change Cipher Spec
「變動祕鑰規範」,用於通知接收方後續的通信數據將在新協商的祕鑰規範保護下交換。
此消息在Finished消息以前被髮送。

客戶端在交換預主祕鑰後,就當即發送了「Change Cipher Spec」消息。

以後,服務端也發送一個「Change Cipher Spec」消息。

Application Data Protocol

應用數據協議
若是握手過程結束一切正常,Alice和Bob就用這條加密信道放心的發送數據了,這些數據都是被加密過的。

http-over-tls

Alert Protocol
警報消息傳達消息的嚴重性(警告或致命)以及警報的描述。 具備致命級別的警報消息致使鏈接當即終止。在這種狀況下,對應於會話的其餘鏈接能夠繼續,可是會話標識符必須無效,防止失敗的會話被用於創建新鏈接。與其餘消息同樣,警報消息按當前鏈接狀態的指定進行加密和壓縮。

警報協議包含不少異常場景,如證書過時、沒有符合密碼套件、未知的ca等,這裏就不一一列出了。

TLS握手簡化流程圖
Client                 Server

ClientHello    ----------->
                   ServerHello
                   Certificate*
                   ServerKeyExchange*
                   CertificateRequest*
          <-----------    ServerHelloDone
Certificate*
ClientKeyExchange
CertificateVerify*
[ChangeCipherSpec]
Finished      ----------->
                  [ChangeCipherSpec]
          <-----------     Finished
Application Data  <----------->  ApplicationData

中括號號標識的協議不屬於握手協議
星號標識的不是必須的握手流程

至此TLS握手過程說完了,但貌似沒有說到**對稱祕鑰(會話祕鑰)**是如何被計算出來的?
咱們知道,經過前面的握手流程,客戶端和服務端都知道了如下信息:

預主祕鑰(計算出來的)
客戶端隨機數
服務端隨機數
經過這三個參數,客戶端和服務端就能夠分別計算出主祕鑰:

master_secret = PRF(pre_master_secret, "master secret",
                          ClientHello.random + ServerHello.random)

master_secret 長度爲48個字節。Master secret是有系列的hash值組成的

PRF (pseudo random function)僞隨機函數,也就是選擇的加密套件中的第四個算法SHA384。計算完主祕鑰,就應當把預主祕鑰從內存中刪除。
PRF算法須要一個「祕鑰」、一個「種子」和一個「文本標識」做爲輸入,而後產生一個不定長的輸出。
其中的「祕鑰」就是預主祕鑰,「種子」就是兩個隨機數的和,「文本標識」就是 master secret。

由於客戶端和服務端的輸入參數都是同樣的,因此計算出來的主祕鑰也是一致的。

主祕鑰是用來作對稱加密的祕鑰的麼?
不是,須要由主祕鑰再次計算,主祕鑰在建立會話祕鑰時做爲一個熵來源。最終計算出來的結果以下:

客戶端寫入MAC密鑰
服務器寫入MAC密鑰
客戶端寫入加密密鑰
服務器寫入加密密鑰
客戶端寫入IV
服務端寫入IV

其實是生成了兩個會話祕鑰:

MAC(Message Authentication Code),是一個數字簽名,用來驗證數據的完整性,能夠檢測到數據是否被串改。
當客戶端向服務端發送消息時,使用「客戶端寫入MAC祕鑰」生成消息摘要附加在消息結尾,使用「客戶端寫入祕鑰」加密;服務端接收到消息後,使用「客戶端寫入祕鑰」解密,使用「客戶端寫入MAC祕鑰」作消息摘要並對比兩次摘要結果。
反過來則是,服務端向客戶端發送消息時,使用「服務端寫入MAC祕鑰」生成消息摘要附加在消息結尾,使用「服務端寫入祕鑰」加密;客戶端接收到消息後,使用「服務端寫入祕鑰」解密,使用「服務端寫入MAC祕鑰」作消息摘要並對比兩次摘要結果。
若是須要在TLS層壓縮數據,則在加密以前先壓縮。

一些AEAD(認證加密)祕鑰套件可能額外須要一個客戶端寫入向量和服務端寫入向量

那麼這些值是怎麼計算出來的呢?

key_block = PRF(master_secret,「key expansion」,server_random + client_random); 
          = P_hash(master_secret, 「key expansion"+server_random + client_random)

P_hash定義爲: 
P_hash(secret, seed) = HMAC_hash(secret, A(1) + seed) +
                        HMAC_hash(secret, A(2) + seed) +
                        HMAC_hash(secret, A(3) + seed) + ...
                        
A(0) = seed;
A(i) = HMAC_hash(secret, A(i-1));
...

HMAC: 基於消息認證碼的哈希算法,也就是對消息進行哈希運算時添加一個祕鑰。

以TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384爲例,AES256會話加密算法須要32字節的會話祕鑰,而咱們須要2個會話祕鑰(2 * 32)和2個MAC祕鑰(2 * 48),就是2 * 32 + 2 * 48= 160字節。而摘要算法SHA384每次的運算輸出爲48字節,爲了能知足160個字節,至少須要計算4次,拼接後獲得172字節的輸出。

而後按照上述順序:

0~47字節爲「客戶端寫入MAC祕鑰」
48~95字節爲「服務器寫入MAC祕鑰」
96~127字節爲「客戶端寫入加密祕鑰」
128~159字節爲「服務端寫入加密祕鑰」
剩下的12字節則捨棄。

總結:

握手過程當中,客戶端和服務端交換了哪些東西?

兩個隨機數
DH算法的公鑰
證書
握手過程當中,哪些消息是通過加密的?加密的目的是什麼?

Server/Client Key Exchange 使用服務器私鑰加密,防止中間人篡改
Finished 使用主祕鑰加密並簽名,驗證主祕鑰是否正確生成和握手消息是否被篡改
若是服務端的私鑰泄漏,壞人可否解密會話數據?
RSA 能夠
DH 不能夠
PSK 不能夠

參考:TLS握手協議分析與理解——某HTTPS請求流量包分析

解密應用數據方式:

啓動Chrome並制定SSL的日誌文件

sudo /Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome  --ssl-key-log-file=/Users/joye/Downloads/sslkeylog.log

在WireShark中Preferences->Protocols->SSL-(Pre)-Master-Secret log filename設置日誌文件

相關文章
相關標籤/搜索