从 SSLTLS 的底层实现来看 网络安全的庞大复杂体系
文章目錄
- 前言
- 1. HTTP協議通信的問題
- 1.1 tcpdump 抓取http 請求包
- 1.2 報文分析
- 1.3 HTTP 協議問題
- 2. SSL & TLS 協議的基本介紹和歷史演進
- 3. TLS 1.2 實現加密傳輸的過程
- 3.1 TLS HandShake 協議概覽
- 3.2 第一次握手:ClientHello
- 3.3 第二次握手:從ServerHello 到 ServerHelloDone
- 3.3.1 ServerHello
- 3.3.2 Server Certificate
- 3.3.3 ServerKeyExchange
- 3.3.4 CertificateRequest
- 3.3.5 ServerHelloDone
- 3.4 第三次握手
- 3.4.1 Client Certificate
- 3.4.2 Client Key Exchange Message
- 3.4.3 Certificate Verify
- 3.4.4 Finished
- 4. 參考文獻
前言
近期工作需要接入http 接口到存儲引擎,因為公司內網 需要保證內網安全,所有的http請求通信都需要通過 https,也就是安全的http 協議才行。這個時候,實現的http 接口也就需要支持 SSL & TLS 。這里會產生一些疑惑,http請求和https 請求的本質區別是什么?為什要有https ,也就是SSL & TLS的出現,他們要解決http 解決不了的什么問題?
這不了解還好,一了解 并深入底層 才發現 SSL和TLS 的發展史已經接近整個互聯網的發展史,他們底層的技術棧已經被作為互聯網信息傳輸的基礎,是一個龐大的系統。然后就不得不感嘆技術之廣之深,習以為常的技術卻深藏奧秘 和 互聯網的精髓,再看看我這種每天只想做一只只完成工作的咸魚,相比互聯網前沿探索的先輩來說真是自愧不如。
還是回歸正題,先做一個SSL & TLS的筆記記錄吧。
本文將從如下幾個方面展開:
- 當前http 協議通信的問題?
- SSL & TLS 協議的基本介紹和歷史演進?
- 然后從 它們的實現過程 來看 https 如何通過 SSL&TLS 解決http 的問題?
1. HTTP協議通信的問題
互聯網是一個開放的環境,任何人持有一個接入網絡的終端,都能夠去訪問其他任何服務器。而終端和服務器之間的通信內容都有可能被其他人看到/截取/修改。我們看看不使用https 通信的情況下,能夠看到通信雙方都互相接收發送什么內容?
1.1 tcpdump 抓取http 請求包
-
開啟一個終端:
tcpdump tcp port 80 -n -A -s 0監聽通過80端口的所有請求信息。 -
開啟另一個終端:通過
curl發送http請求curl -d "city=dongguan&appkey=8010132dcf54491a4eaa387f4db61774" "http://way.jd.com/he/freeweather"可以看到這里向url
http://way.jd.com/he/freeweather發送的是一個post請求,將本地用戶的請求信息帶著發送給了這個 url。最后會收到遠端服務器返回的一個json字符串,表示本地用戶的請求結果。
{"code":"10000","charge":false,"msg":"查詢成功", \"result":{"HeWeather5":[{"aqi":{"city": \{"aqi":"28","co":"0.5","no2":"18","o3":"87"...
1.2 報文分析
這個時候我們再去 tcpdump 開啟的終端看看抓取到的通信的內容。
如下為截取的抓取結果,后面其實還有http 的四次揮手,不過不影響我們分析http 請求。
可以看到很明顯的一點,我們通過 http 發送的不安全的請求,在第三方抓包的時候能夠看到雙方通信的所有內容,也就是明文通信。假如我們是一個登陸網站,那我們post 到遠端服務器的個人用戶名/密碼/其他信息 的所有數據都會被第三方看到,當然看到的話也能夠被修改,這對于處于互聯網中的個人隱私來說簡直是一個災難。
這個時候,我們把curl請求的http請求切換為https,能夠看到抓取到的報文信息就看不到用戶信息了,基本都是密文。
1.3 HTTP 協議問題
綜上,我們能夠很明顯得看到 http 不加密協議的問題:
- 竊聽風險(eavesdropping):第三方可以獲知通信內容。
- 篡改風險(tampering): 第三方可以修改通信內容
- 冒充風險(pretending): 第三方可以冒充他人參與通信。
而,加上了HTTPS 即 SSL & TLS 安全協議,為了解決以上是三個風險,我們期望能夠達到:
-
所有信息都是加密傳播,第三方無法竊聽。
-
具有校驗機制,一旦被篡改,通信雙方會立刻發現。
-
配備身份證書,防止身份被冒充。
第一點的加密傳輸,我們能夠從 tcpdump 的抓包內容中看到這個特性,第二第三點則是SSL & TLS 協議棧背后的通信的細節,我們接下來將描述這個過程。
2. SSL & TLS 協議的基本介紹和歷史演進
前面我們說 安全加密通信 都是將SSL和TLS 放在一起進行描述,SSL(Secure Socket Layer)和 TLS(Transport Layer Security) 都是加密協議,它們從作用上并沒有區別,都是為了解決加密傳輸的問題。事實上,TLS 是 一個 SSL 比較新的版本,TSL 功能上和SSL的區別是為了解決早期 SSL的一些安全性問題。
SSL & TLS 的發展史如下:
- SSL 1.0 – 因為一些安全性問題,從來沒有被公開過
- SSL 2.0 – 1995年發布。因為一些安全性問題,在2011年被廢棄。
- SSL 3.0 – 1996年發布。因為一些安全性問題,在2015年被廢棄。
- TLS 1.0 – 在1999年作為SSL 3.0 升級版本,已經在2020年廢棄。
- TLS 1.1 – 在2006年發布,在2020年廢棄。
- TLS 1.2 – 2008年發布。
- TLS 1.3 – 2018年發布。
也就是我們現在瀏覽器 以及 企業內部 的加密通信大多是TLS1.2 版本及以上,后續介紹的SSL & TLS 如何進行安全通信的細節是在TLS1.2 版本之上進行的。
TLS/SSL 的基本加密思路是通過 公鑰加密 ,也就是客戶端會先向服務端索要 公鑰,然后用公鑰加密信息,服務端收到信息再通過公鑰進行解密。
3. TLS 1.2 實現加密傳輸的過程
總體介紹一下TLS/SSL 的加密過程如下:
-
客戶端向服務器端索要并驗證公鑰。
-
雙方協商生成"對話密鑰"。
-
雙方采用"對話密鑰"進行加密通信。
在TLS 1.2 版本中,整個協議棧由兩個協議層組成:TLS record protocol 和 TLS HandShake protocol ,而在這兩個TLS 本身的協議層之下則是一些更加可靠的傳輸協議(TCP這種)。
其中 TSL record protocol 主要有如下兩個特性:
- 保證鏈接是私密的。這一層會對數據進行加密,并且保證用于當前通信的公有密鑰是唯一的,也就是只有連接者和服務器知道具體的公鑰。
- 保證鏈接是可靠的。
在上面的協議之下,TLS 還維護了一個 TLS HandShake protoco L,這個協議是TLS 解決 http 三個主要問題的核心協議,其允許服務器和客戶端之間在進行真正的數據傳輸之前進行互相驗證并協商加密算法 和 加密密鑰。
接下來我們要詳細看一下TLS HandShake protocol 的協議實現過程。
3.1 TLS HandShake 協議概覽
TLS 握手協議的步驟主要是如下幾步(我們前面用tcpdum 抓到的三次握手):
- 交換Hello Message, 主要進行一些加密算法 的驗證 以及 一些偽隨機數的交換。
- 交換一些必要的加密參數,來允許客戶端和 server 認同 premaster secret的值.
- 交換證書和加密信息 來讓客戶端和服務端進行互相身份的驗證。
- 通過 premaster secret 生成一個master 密鑰 和 交換一些隨機值。
- 將這一些安裝參數提供給 上層的 TLS Record Protocol.
- 允許客戶端和服務端在他們本地計算安全參數,從而保證即使有攻擊發生,鏈接請求也不會在客戶端或者服務端建立成功。
從服務端和客戶端的角度來看,主要有如下幾個步驟:
Client ServerClientHello -------->ServerHelloCertificate*ServerKeyExchange*CertificateRequest*<-------- ServerHelloDoneCertificate*ClientKeyExchangeCertificateVerify*[ChangeCipherSpec]Finished -------->[ChangeCipherSpec]<-------- FinishedApplication Data <-------> Application Data
關于底層的HandShake結構體類型如下:
enum {hello_request(0), client_hello(1), server_hello(2),certificate(11), server_key_exchange (12),certificate_request(13), server_hello_done(14),certificate_verify(15), client_key_exchange(16),finished(20), (255)
} HandshakeType;struct {HandshakeType msg_type; /* handshake type */uint24 length; /* bytes in message */select (HandshakeType) {case hello_request: HelloRequest;case client_hello: ClientHello;case server_hello: ServerHello;case certificate: Certificate;case server_key_exchange: ServerKeyExchange;case certificate_request: CertificateRequest;case server_hello_done: ServerHelloDone;case certificate_verify: CertificateVerify;case client_key_exchange: ClientKeyExchange;case finished: Finished;} body;
} Handshake;
3.2 第一次握手:ClientHello
首先 客戶端 和服務器進行第一個的鏈接的時候會 發送ClientHello 請求到服務器。這個階段主要是雙方交換一些安全屬性的信息。
其中ClientHello的消息結構體如下:
struct {ProtocolVersion client_version;Random random;SessionID session_id;CipherSuite cipher_suites<2..2^16-2>;CompressionMethod compression_methods<1..2^8-1>;select (extensions_present) {case false:struct {};case true:Extension extensions<0..2^16-1>;};
} ClientHello;
結構體內部的成員即是 這個 Request 客戶端要發送給服務端的內容,主要包括
client_version:當前TLS 協議的版本號random: 一個客戶端生成的偽隨機數,主要由兩部分構成gmt_unix_time和random_bytes,當前系統時間和一個28bytes的偽隨機數。session_id: 客戶端希望本次鏈接的標識。Ciper_suites:表示客戶端支持的一些加密方式列表(RSA等)。compression_methods:一個客戶端支持的 壓縮方式的列表。
3.3 第二次握手:從ServerHello 到 ServerHelloDone
第二次握手包含五個階段,主要是服務端的回復內容。
主要的內容如下:
- 確認使用的加密通信版本。如果版本不一致(比如TLS 1.2),則服務器關閉通信功能
- 一個服務器生成的隨機數,后續用于生成對話密鑰。
- 確認使用的加密方法,比如RSA
- 服務器的認證證書。
- Extensions,類似請求客戶端證書,比如某一些企業的請求接入,需要客戶端提供企業之前提供過的認證才行。
以上內容主要被以下幾個請求依次發送:
3.3.1 ServerHello
這個結構體內容如下:
struct {ProtocolVersion server_version;Random random;SessionID session_id;CipherSuite cipher_suite;CompressionMethod compression_method;select (extensions_present) {case false:struct {};case true:Extension extensions<0..2^16-1>;};
} ServerHello;
server_version: server 支持的 TLS 協議版本random: server 會在 client 發送過來的隨機數基礎上再生成一個隨機數。session_id: 收到client 發送過來的session_id 之后,會從自己的session列表中查找這個id,找到了則直接復用。否則,server的session_id 會直接填充一個新的session_id返回給客戶端,與此同時 也會決定使用服務端的加密算法。cipher_suite: 從客戶端發送過來的 加密算法列表中選擇一個加密算法。如果前面的session_id 從服務端維護的列表中找到了,則直接復用這個session_id 的加密算法。compression_method:服務端選擇客戶端發來的壓縮算法列表中的一個。當然,如果復用了session_id,壓縮算法同樣也會被復用。
3.3.2 Server Certificate
用于發送服務器的認證證書到客戶端。再ServerHello 消息發送之后發送,消息結構體如下:
struct {ASN.1Cert certificate_list<0..2^24-1>;
} Certificate;
certificate_list證書列表。第一個證書必須是發送者的證書。后續的每一個證書必須證明前面的證書是合理的。
同樣,如果服務端想要客戶端的證書,那客戶端發送過來的證書也需要按照這種方式發送。
3.3.3 ServerKeyExchange
在服務端發送了認證證書之后會發送。這個請求發送的原因是 服務端認為自己發送給客戶端的認證證書并沒有包含足夠的數據來允許客戶端交換自己的 premaster key。如果使用如下交換密鑰算法則客戶端會被允許交換:DHE_DSS, DHE_RSA, DH_anon;使用如下交換算法,則客戶端不會交換master key:RSA, DH_DSS, DH_RSA。
它的數據結構如下:
struct {select (KeyExchangeAlgorithm) {case dh_anon:ServerDHParams params;case dhe_dss:case dhe_rsa:ServerDHParams params;digitally-signed struct {opaque client_random[32];opaque server_random[32];ServerDHParams params;} signed_params;case rsa:case dh_dss:case dh_rsa:struct {} ;/* message is omitted for rsa, dh_dss, and dh_rsa *//* may be extended, e.g., for ECDH -- see [TLSECC] */};
} ServerKeyExchange;
-
param: 服務器key的交換參數
主要包含一些交換算法:enum { dhe_dss, dhe_rsa, dh_anon, rsa, dh_dss, dh_rsa/* may be extended, e.g., for ECDH -- see [TLSECC] */} KeyExchangeAlgorithm;struct {opaque dh_p<1..2^16-1>;opaque dh_g<1..2^16-1>;opaque dh_Ys<1..2^16-1>; } ServerDHParams; /* Ephemeral DH parameters */ -
signed_params: 對于非匿名密鑰的交換,服務器會附加這個參數,標識自己(非匿名密鑰 太了解)
3.3.4 CertificateRequest
對于非匿名服務器(企業認證的服務器)來說,會為注冊用戶發送一個客戶端證書,注冊用戶接入的時候服務端也會請求客戶端的認證證書。也就是整體描述 從ServerHello 到 ServerHelloDone 內容的第五段消息。
消息結構體如下:
struct {ClientCertificateType certificate_types<1..2^8-1>;SignatureAndHashAlgorithmsupported_signature_algorithms<2^16-1>;DistinguishedName certificate_authorities<0..2^16-1>;
} CertificateRequest;
-
certificate_types服務端為客戶端提供的認證證書類型列表enum {rsa_sign(1), dss_sign(2), rsa_fixed_dh(3), dss_fixed_dh(4),rsa_ephemeral_dh_RESERVED(5), dss_ephemeral_dh_RESERVED(6),fortezza_dms_RESERVED(20), (255) } ClientCertificateType; -
supported_signature_algorithms, 服務端支持的簽名/hash 驗證算法的列表 -
certificate_authorities可信的出版證書機構的名稱。
3.3.5 ServerHelloDone
服務端在前面的消息發送完成之后會發送這個消息,表示服務端的消息已經發送完畢,客戶端可以進行證書校驗 以及 判斷是否能夠接受服務端的公鑰,而服務端則會等待客戶端的回復。
3.4 第三次握手
客戶端校驗服務端的認證證書,如果證書不是可信的機構頒布 或者 證書中的域名與實際的域名不匹配,或者證書已經過期,就會向客戶端顯示一個告警,由客戶端選擇是否繼續訪問。
如果證書沒有問題,客戶端就會從證書中取出服務端的公鑰,向服務端發送如下內容:
- 一個隨機數。該隨機數用服務器公鑰加密,防止被竊聽。
- 編碼改變通知,表示隨后的信息都將用雙方商定的加密方法和密鑰發送
- 客戶端握手結束通知,表示客戶端的握手階段已經結束。這一項同時也是前面發送的所有內容的hash值,用來供服務器校驗。
- 如果服務端需要客戶端提供可信證書,那客戶端也需要發送一個認證證書。
這一次握手對應客戶端的三個請求,從Client Certificate 到 Finish 。
3.4.1 Client Certificate
這個請求發送的要求是 服務端 請求客戶端的認證證書。
證書的格式和服務端的類似。
3.4.2 Client Key Exchange Message
客戶端的編碼改變通知。這個請求是無論什么時候必須要發送給服務端的。表示客戶端任何 和 服務端協商的premaster-key,后續的通信都將通過這個密鑰進行。
選擇哪一種編碼算法取決于服務端ServerKeyExchanged 請求中選擇的 交換算法。
消息結構體如下:
struct {select (KeyExchangeAlgorithm) {case rsa:EncryptedPreMasterSecret;case dhe_dss:case dhe_rsa:case dh_dss:case dh_rsa:case dh_anon:ClientDiffieHellmanPublic;} exchange_keys;
} ClientKeyExchange;
3.4.3 Certificate Verify
客戶端認證服務端的證書。
struct {digitally-signed struct {opaque handshake_messages[handshake_messages_length];}
} CertificateVerify;
這個結構體中的 handshake_messages 變量引用了從 client hello 到 當前消息之前的所有握手階段的消息。
3.4.4 Finished
這個完成握手的請求會在客戶端的編碼改變請求 以及 證書驗證請求發送之后發送。Finished 請求是一個被之前握手階段協商的算法、公鑰和對稱密鑰保護的消息。在這個消息發送完畢收到服務端對客戶端Finished 消息回復之后 兩者將通過協商后的加密算法進行通信。
再次看看整個https 的三次握手步驟:
Client ServerClientHello -------->ServerHelloCertificate*ServerKeyExchange*CertificateRequest*<-------- ServerHelloDoneCertificate*ClientKeyExchangeCertificateVerify*[ChangeCipherSpec]Finished -------->[ChangeCipherSpec]<-------- FinishedApplication Data <-------> Application Data
可以看到,服務端收到客戶端的Finished消息之后,會回復:
- 服務端的編碼改變通知,表示后續服務端將使用協商好的對稱密鑰加密 以及 pre-masterkey 公鑰進行解密。
- 服務端結束握手的通知。
之后就是用協商好的加密密鑰 進行 應用數據的加解密傳輸了。
可以看到,在第三次握手結束后,服務端和客戶端都擁有了三個隨機數(客戶端ClientHello生成的,服務端ServerHello生成的,客戶端ClientKeyExchangeMessage生成的),這三個隨機數能夠保證整個加密過程的保密性(密文很難被解析到);同時 認證證書 的存在 也保證了通信的可靠性(也就是為什么不推薦大家訪問瀏覽器報警證書不匹配問題的網站,訪問的網站沒有使用版本匹配/最新 的證書,無法保證傳輸數據的保密性)。
4. 參考文獻
https://kinsta.com/knowledgebase/tls-vs-ssl/
TLS 1.2 reference detail
總結
以上是生活随笔為你收集整理的从 SSLTLS 的底层实现来看 网络安全的庞大复杂体系的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 玛咖多少钱一斤?
- 下一篇: 飞来游器,上帝之火,还有一个游戏是哪部电