浅谈 HTTPS
淺談 HTTPS
相信大家都會(huì)注意到很多網(wǎng)站的地址欄上會(huì)出現(xiàn)一個(gè)綠色的小鎖,比如:
如果地址欄中出現(xiàn)了這樣子的綠色小鎖,則表示當(dāng)前頁面是通過 HTTPS 傳遞的,只要證書是正確的,那么目前來說可以保證網(wǎng)頁內(nèi)容沒有被篡改以及即使第三者截取到了通信內(nèi)容也無法從密文獲得明文。
什么是 HTTPS?
HTTPS 類似于 HTTP 協(xié)議的“安全版”,其全稱為超文本傳輸安全協(xié)議(英文:HyperText Transfer Protocol Secure,縮寫 HTTPS),以下引用自維基百科:
超文本傳輸安全協(xié)議是一種透過計(jì)算機(jī)網(wǎng)絡(luò)進(jìn)行安全通訊的傳輸協(xié)議。HTTPS 經(jīng)由 HTTP 進(jìn)行通訊,但利用 SSL/TLS 來加密封包。HTTPS 開發(fā)的主要目的,是提供對(duì)網(wǎng)站服務(wù)器的身份認(rèn)證,保護(hù)交換資料的隱私與完整性。這個(gè)協(xié)議由網(wǎng)景公司(Netscape)在1994年首次提出,隨后擴(kuò)展到互聯(lián)網(wǎng)上。HTTPS 的用途就是在不安全的網(wǎng)絡(luò)上建立安全的信道,用于傳輸敏感數(shù)據(jù)(比如信用卡號(hào)、密碼等)或者用于保護(hù)互聯(lián)網(wǎng)賬戶不被盜取、保證網(wǎng)頁數(shù)據(jù)的正確性等。
HTTPS 有什么用?
通過 HTTP 協(xié)議傳輸?shù)臄?shù)據(jù)就像 Tom 給 Jerry 寫信,Tom 把寫好的信直接交給了郵遞員,信封沒有密封甚至直接沒有信封,郵遞員可以隨意查看 Tom 給 Jerry 的信件、修改信件里的內(nèi)容甚至冒充 Tom 與 Jerry 進(jìn)行通信。
這明顯是不安全的。
Tom 為了不讓郵遞員偷看他給 Jerry 的信件并確保自己的信件不會(huì)被替換,決定在信的最后附上自己的簽名,并在信封上加上火漆印章(一旦信件被私自拆閱則印章就會(huì)損毀),這時(shí),如果 Tom 再給 Jerry 寫信,Jerry 只需要在收到信件的時(shí)候檢查信封上的火漆印章和信件最后的簽名,就可以確保收到的信件沒有被郵遞員拆閱或者替換過。
在這個(gè)例子中,Tom 和 Jerry 分別代表客戶端和服務(wù)器(或者服務(wù)器與服務(wù)器、客戶端與客戶端),郵遞員相當(dāng)于不安全的網(wǎng)絡(luò)信道(比如包含 ISP、代理服務(wù)器等),而信件就相當(dāng)于 HTTP 請(qǐng)求中的內(nèi)容。Tom 簽名及蓋火漆印章的過程相當(dāng)于加密,驗(yàn)證簽名和火漆印章完整性的時(shí)候就相當(dāng)于身份驗(yàn)證和解密。
在實(shí)際中,不使用 HTTPS 的風(fēng)險(xiǎn)不僅是數(shù)據(jù)被隨時(shí)監(jiān)視,無良的 ISP 可能還會(huì)給網(wǎng)頁上加上廣告,甚至可以隨意增刪通過 HTTP 傳輸?shù)木W(wǎng)站代碼,這非常危險(xiǎn)。而 HTTPS 可以避免這些風(fēng)險(xiǎn)。
HTTPS 連接的握手過程
我們可以使用 curl 命令來簡(jiǎn)略查看建立 HTTPS 時(shí)的握手過程,在命令行中執(zhí)行:curl -v -I -L https://ymfe.org
能得到如下的輸出:
簡(jiǎn)單說明一下連接的建立過程:
# 表示建立了和 ymfe.org 服務(wù)器 443 端口的連接。 Connected to ymfe.org (123.56.155.201) port 443 (#0) # 客戶端發(fā)出 client_hello 消息。 TLSv1.2 (OUT), TLS handshake, Client hello (1): # 服務(wù)器發(fā)出 server_hello 消息。 TLSv1.2 (IN), TLS handshake, Server hello (2): # 服務(wù)器發(fā)出 certificate 消息。 TLSv1.2 (IN), TLS handshake, Certificate (11): # 服務(wù)器發(fā)出 server_key_exchange 消息。 TLSv1.2 (IN), TLS handshake, Server key exchange (12): # 服務(wù)器發(fā)出 server_done 消息。 TLSv1.2 (IN), TLS handshake, Server finished (14): # 客戶端發(fā)出 client_key_exchange 消息。 TLSv1.2 (OUT), TLS handshake, Client key exchange (16): # 客戶端發(fā)出加密后的 client_hello 消息。 TLSv1.2 (OUT), TLS change cipher, Client hello (1): # 客戶端發(fā)出 hello_done 消息。 TLSv1.2 (OUT), TLS handshake, Finished (20): # 服務(wù)器將加密后的 client_hello 消息發(fā)回。 TLSv1.2 (IN), TLS change cipher, Client hello (1): # 握手結(jié)束。 TLSv1.2 (IN), TLS handshake, Finished (20): # SSL 連接采用 ECDHE-RSA-AES256-GCM-SHA384 密碼套件。 # ECDHE 表示密鑰交換方法采用橢圓曲線迪菲-赫爾曼交換方法 # RSA 表示密鑰交換中使用的簽名方式 # AES-256-GCM 表示的是對(duì)稱加密算法 # SHA-384 表示的是內(nèi)容完整性校驗(yàn)使用的哈希算法 SSL connection using TLSv1.2 / ECDHE-RSA-AES256-GCM-SHA384 # 之后的幾行包含了證書的內(nèi)容,包括有效時(shí)間、常用名、證書簽發(fā)機(jī)構(gòu)等。 Server certificate: # Common Name 為 ymfe.orgsubject: CN=ymfe.org# 在此時(shí)間之前無效start date: Aug 31 05:50:00 2017 GMT# 在此時(shí)間之后無效expire date: Nov 29 05:50:00 2017 GMT# 域名和證書的域名匹配subjectAltName: host "ymfe.org" matched cert's "ymfe.org"# 簽發(fā)者是 Let's Encryptissuer: C=US; O=Let's Encrypt; CN=Let's Encrypt Authority X3握手的詳細(xì)步驟
client_hello
這一步中,瀏覽器會(huì)向服務(wù)器發(fā)出建立 HTTPS 的請(qǐng)求,在請(qǐng)求中,瀏覽器會(huì)帶上一些建立連接的必要信息(注意:這一步的信息全都是明文的),包括:
server_hello
客戶端在發(fā)出 client_hello 消息之后,會(huì)等待服務(wù)器返回 server_hello 消息,包含和 client_hello 相同的參數(shù)。一般來說,參數(shù)結(jié)構(gòu)如下:
(certificate) (+ server_key_exchange) (+ certificate_request) + server_hello _done
通常來說,服務(wù)器會(huì)在 certificate 消息中發(fā)送其自身的證書供客戶端進(jìn)行驗(yàn)證,這個(gè)消息包含一個(gè)或一組 X. 509 證書。如果采用的是固定 Diffie-Hellman 方法(更多關(guān)于 Diffie-Hellman 的內(nèi)容請(qǐng)查看維基百科上的詞條 Diffie-Hellman),此 certificate 消息將使用服務(wù)器 Diffie-Hellman 公鑰參數(shù)作為服務(wù)器的密鑰交換消息。有一種密鑰交換方法——匿名 Diffie-Hellman 方法,不需要 certificate 消息。該算法使用基本的 Diffie-Hellman 算法,在向?qū)Ψ桨l(fā)送其 Diffie-Hellman 公鑰參數(shù)時(shí),不進(jìn)行認(rèn)證(因?yàn)闆]有認(rèn)證,所以這種方法容易受到中間人攻擊)。
接著,除了兩種情況:(1) 服務(wù)器發(fā)送了帶有固定 Diffie-Hellman 參數(shù)的證書;(2) 使用 RSA 密鑰交換;不需要發(fā)送 server_key_exchange 消息,其余情況服務(wù)器均會(huì)發(fā)送 server_key_exchange 消息,用以向客戶端發(fā)送之后用以生成密鑰的各項(xiàng)參數(shù)。該消息的內(nèi)容根據(jù)密鑰交換算法不同而不同,具體內(nèi)容不在本文討論之列。該項(xiàng)參數(shù)作為 server_key_exchange 消息的第一項(xiàng)值。
然后,服務(wù)器將對(duì)消息使用散列函數(shù)(根據(jù)不同簽名算法選擇不同的散列函數(shù),例如 MD5 或者 SHA-1 等)對(duì)客戶端發(fā)來的隨機(jī)數(shù)、服務(wù)器生成的隨機(jī)數(shù)以及 server_key_exchange 消息中的各項(xiàng)參數(shù)進(jìn)行求值并使用服務(wù)器的私鑰進(jìn)行簽名。該值作為 server_key_exchange 消息中的第二項(xiàng)值。
如果服務(wù)器需要驗(yàn)證客戶端的身份(即雙向認(rèn)證),則會(huì)發(fā)送 certificate_request 消息,請(qǐng)求客戶端發(fā)送其自身的證書。
最后,服務(wù)器發(fā)送 server_hello_done 消息,表明服務(wù)器的 hello 相關(guān)的消息結(jié)束。在發(fā)送此消息之后,服務(wù)器會(huì)等待客戶端應(yīng)答,該消息沒有參數(shù)。
(certificate) + client_key_change (+ certificate_verify)
客戶端在收到服務(wù)器發(fā)來的 server_hello_done 消息之后,會(huì)驗(yàn)證服務(wù)器提供的證書是否合法,并檢查 server_hello 的各項(xiàng)參數(shù)。如果驗(yàn)證通過,則客戶端會(huì)向服務(wù)器發(fā)送一條或多條消息。
如果服務(wù)器發(fā)送了 certificate_request 消息,且客戶端有合適的證書,則客戶端會(huì)發(fā)送一條 certificate 消息,否則會(huì)發(fā)送一個(gè)“無證書警報(bào)”。
然后客戶端會(huì)發(fā)送 client_key_exchange 消息,其內(nèi)容取決于密鑰交換的類型:
最后,如果客戶端具有證書且證書具備簽名能力(即除了帶固定 Diffie-Hellman 參數(shù)外的所有證書),可以發(fā)送一個(gè) certificate_verify 消息來提供對(duì)客戶端證書的精確認(rèn)證。
change_cipher_spec + finished
經(jīng)過以上步驟,客戶端和服務(wù)器已經(jīng)可以通過得到的消息計(jì)算出 Master Key 了。從現(xiàn)在開始,客戶端和服務(wù)器都將開始使用協(xié)商好的加密算法、密鑰進(jìn)行通信,在正式傳遞消息之前會(huì)計(jì)算 Master Key 及 Master Key 和之前握手過程中收到的所有信息的 hash,并通過協(xié)商好的加密算法使用 Master Key 加密,作為 change_cipher_spec 消息的內(nèi)容,接著發(fā)送 finished 消息。服務(wù)器在收到客戶端發(fā)來的 change_cipher_spec 和 finished 消息之后,也會(huì)計(jì)算 Master Key 并使用協(xié)商好的加密算法和 Master Key 計(jì)算 Master Key 和之前握手過程中收到的所有信息的 hash,發(fā)回給客戶端用以驗(yàn)證。至此,握手階段結(jié)束,之后就可以交換應(yīng)用層的內(nèi)容了。
如何加密應(yīng)用層內(nèi)容
細(xì)心的讀者可能發(fā)現(xiàn),在建立連接的過程中,交換的僅僅是密鑰而不是內(nèi)容,為什么這么復(fù)雜的過程僅僅交換了密鑰呢?
對(duì)稱加密和非對(duì)稱加密
常用的加密方式分為兩種:
- 對(duì)稱加密:加密和解密使用的是相同的密鑰。
- 非對(duì)稱加密:加密和解密使用的不是相同的密鑰,而是一對(duì)密鑰對(duì),分別稱為公鑰和私鑰。
對(duì)稱加密最大的特點(diǎn)就是通信雙方都需要知道加密密鑰,這對(duì)于互聯(lián)網(wǎng)上的服務(wù)器和客戶端來說,在事先沒有建立安全信道的情況下安全地傳送密鑰幾乎是不可能的。不過相較于非對(duì)稱加密來說,對(duì)稱加密的優(yōu)點(diǎn)就是快。
非對(duì)稱加密最大的特點(diǎn)就是通信雙方只需要知道密鑰對(duì)中的一個(gè),而且使用公鑰加密的內(nèi)容只能通過私鑰解密,使用私鑰加密的內(nèi)容只能通過公鑰解密。對(duì)于一個(gè)實(shí)體來說,公鑰可以公開給任何人,只需要保證自身的私鑰的安全,就可以保證其與另一個(gè)實(shí)體的通信內(nèi)容不會(huì)被第三者竊取。
HTTPS 用了哪種加密方法?
在 HTTPS 中,對(duì)稱加密和非對(duì)稱加密都用到了。非對(duì)稱加密可以在不安全的信道上傳遞秘密內(nèi)容,但是由于通常使用的非對(duì)稱加密方法相較于對(duì)稱加密算法慢很多,因此在 HTTPS 中僅使用非對(duì)稱加密算法交換對(duì)稱密鑰,交換密鑰之后的通信內(nèi)容均使用對(duì)稱加密算法加密和解密,這樣既可以保證密鑰的安全也可以保證內(nèi)容的加解密速度,這對(duì)于移動(dòng)端設(shè)備來說至關(guān)重要。
擴(kuò)展閱讀
中間人攻擊
中間人攻擊(Man In The Middle Attack,簡(jiǎn)稱 MITM),是指攻擊者與原本通信的兩個(gè)實(shí)體分別建立通信,并交換攻擊者所收到的數(shù)據(jù),讓原本通信的兩個(gè)實(shí)體誤以為自己在一條加密的信道中和對(duì)方直接對(duì)話,但其實(shí)整個(gè)對(duì)話過程都直接受到攻擊者的控制,攻擊者可以隨意增加、刪除、修改通信的內(nèi)容。一般來說,加密協(xié)議都會(huì)加入一些特殊的方法來實(shí)現(xiàn)通信雙方的互相認(rèn)證,以避免中間人攻擊。比如 HTTPS 中就使用證書機(jī)制來防止中間人攻擊。
之前提到匿名 Diffie-Hellman 方法易受中間人攻擊,就是因?yàn)槠洳粚?duì)秘密內(nèi)容(即 Diffie-Hellman 公鑰參數(shù))進(jìn)行簽名認(rèn)證導(dǎo)致的。在這個(gè)過程中,服務(wù)器向客戶端發(fā)送的公鑰參數(shù)如果被攻擊者截獲并替換為自己的公鑰參數(shù),那么攻擊者就可以偽裝成服務(wù)器和客戶端分別和客戶端和服務(wù)器進(jìn)行對(duì)話,而且可以完全控制通信的內(nèi)容。
SNI
當(dāng)進(jìn)行 SSL/TLS 握手時(shí),服務(wù)器會(huì)提供自身的證書給客戶端以供客戶端驗(yàn)證。但是如果一臺(tái)服務(wù)器上托管了多個(gè) HTTPS 站點(diǎn),那么服務(wù)器提供的證書可能就是錯(cuò)誤的。而對(duì)于 SSL/TLS 握手連接來說,服務(wù)器名稱不匹配會(huì)導(dǎo)致客戶端斷開連接,因?yàn)榉?wù)器名稱不匹配表明可能有人正在進(jìn)行中間人攻擊。
一張證書中包含多個(gè)主機(jī)名是可以的,在之前提到的 curl -v -I -L https://ymfe.org 命令中出現(xiàn)了一個(gè)叫做 subjectAltName 的字段,這個(gè)字段就是用于指定多個(gè)域名的,在 common name 和 subjectAltName 中還可以使用通配符。
一臺(tái)服務(wù)器托管多個(gè)站點(diǎn)是非常常見的。在被托管的站點(diǎn)中,它們可能是同一個(gè)域名下的子域名,也可能完全不是同一個(gè)域名。如果多個(gè)站點(diǎn)都用同一張證書的話,那么服務(wù)器需要知道所有被托管的站點(diǎn)的域名,維護(hù)一個(gè)域名列表,這在很多情況下是不切實(shí)際的。而如果為每個(gè) HTTPS 服務(wù)器都分配一個(gè)獨(dú)立的 IP 的話,不但會(huì)增加成本,還會(huì)惡化 IPv4 地址的枯竭情況。
基于名稱的虛擬主機(jī)可以讓多個(gè) DNS 主機(jī)名指向同一個(gè)服務(wù)器。在客戶端發(fā)起請(qǐng)求的時(shí)候,會(huì)在 HTTP 頭部添加正在請(qǐng)求的主機(jī)名稱,服務(wù)器根據(jù)這個(gè)主機(jī)名稱來提供不同的服務(wù)。而 HTTPS 中,在建立握手之前是不會(huì)發(fā)送任何 HTTP 頭部的,也就無法獲取客戶端正在請(qǐng)求的主機(jī)名稱了。因此,無法使用 HTTP 頭部來決定給客戶端提供哪張證書。
SNI(Server Name Indication,服務(wù)器名稱指示)是一個(gè)擴(kuò)展的 TLS 協(xié)議。這個(gè)協(xié)議允許客戶端在建立 HTTPS 握手時(shí)告知服務(wù)器它正在連接的服務(wù)器的名稱。這就允許服務(wù)器根據(jù)客戶端在握手消息發(fā)來的服務(wù)器名稱來提供正確的 HTTPS 證書,避免因?yàn)樽C書錯(cuò)誤導(dǎo)致握手失敗。
總結(jié)
- 上一篇: django官方文档1.11编翻:1-1
- 下一篇: 服务器出问题排查