淺談 HTTPS

淺談 HTTPS

相信你們都會注意到不少網站的地址欄上會出現一個綠色的小鎖,好比:算法

若是地址欄中出現了這樣子的綠色小鎖,則表示當前頁面是經過 HTTPS 傳遞的,只要證書是正確的,那麼目前來講能夠保證網頁內容沒有被篡改以及即便第三者截取到了通訊內容也沒法從密文得到明文。數組

什麼是 HTTPS?

HTTPS 相似於 HTTP 協議的「安全版」,其全稱爲超文本傳輸安全協議(英文:HyperText Transfer Protocol Secure,縮寫 HTTPS),如下引用自維基百科:瀏覽器

超文本傳輸安全協議是一種透過計算機網絡進行安全通信的傳輸協議。HTTPS 經由 HTTP 進行通信,但利用 SSL/TLS 來加密封包。HTTPS 開發的主要目的,是提供對網站服務器的身份認證,保護交換資料的隱私與完整性。這個協議由網景公司(Netscape)在1994年首次提出,隨後擴展到互聯網上。

HTTPS 的用途就是在不安全的網絡上創建安全的信道,用於傳輸敏感數據(好比信用卡號、密碼等)或者用於保護互聯網帳戶不被盜取、保證網頁數據的正確性等。安全

HTTPS 有什麼用?

經過 HTTP 協議傳輸的數據就像 Tom 給 Jerry 寫信,Tom 把寫好的信直接交給了郵遞員,信封沒有密封甚至直接沒有信封,郵遞員能夠隨意查看 Tom 給 Jerry 的信件、修改信件裏的內容甚至冒充 Tom 與 Jerry 進行通訊。服務器

這明顯是不安全的。網絡

Tom 爲了避免讓郵遞員偷看他給 Jerry 的信件並確保本身的信件不會被替換,決定在信的最後附上本身的簽名,並在信封上加上火漆印章(一旦信件被私自拆閱則印章就會損毀),這時,若是 Tom 再給 Jerry 寫信,Jerry 只須要在收到信件的時候檢查信封上的火漆印章和信件最後的簽名,就能夠確保收到的信件沒有被郵遞員拆閱或者替換過。curl

在這個例子中,Tom 和 Jerry 分別表明客戶端和服務器(或者服務器與服務器、客戶端與客戶端),郵遞員至關於不安全的網絡信道(好比包含 ISP、代理服務器等),而信件就至關於 HTTP 請求中的內容。Tom 簽名及蓋火漆印章的過程至關於加密,驗證簽名和火漆印章完整性的時候就至關於身份驗證和解密。函數

在實際中,不使用 HTTPS 的風險不只是數據被隨時監視,無良的 ISP 可能還會給網頁上加上廣告,甚至能夠隨意增刪經過 HTTP 傳輸的網站代碼,這很是危險。而 HTTPS 能夠避免這些風險。網站

HTTPS 鏈接的握手過程

咱們可使用 curl 命令來簡略查看創建 HTTPS 時的握手過程,在命令行中執行:curl -v -I -L https://ymfe.org加密

能獲得以下的輸出:

curl_https_ymfe.org

簡單說明一下鏈接的創建過程:

# 表示創建了和 ymfe.org 服務器 443 端口的鏈接。
Connected to ymfe.org (123.56.155.201) port 443 (#0) 

# 客戶端發出 client_hello 消息。
TLSv1.2 (OUT), TLS handshake, Client hello (1): 

# 服務器發出 server_hello 消息。
TLSv1.2 (IN), TLS handshake, Server hello (2): 

# 服務器發出 certificate 消息。
TLSv1.2 (IN), TLS handshake, Certificate (11): 

# 服務器發出 server_key_exchange 消息。
TLSv1.2 (IN), TLS handshake, Server key exchange (12): 

# 服務器發出 server_done 消息。
TLSv1.2 (IN), TLS handshake, Server finished (14): 

# 客戶端發出 client_key_exchange 消息。
TLSv1.2 (OUT), TLS handshake, Client key exchange (16): 

# 客戶端發出加密後的 client_hello 消息。
TLSv1.2 (OUT), TLS change cipher, Client hello (1): 

# 客戶端發出 hello_done 消息。
TLSv1.2 (OUT), TLS handshake, Finished (20): 

# 服務器將加密後的 client_hello 消息發回。
TLSv1.2 (IN), TLS change cipher, Client hello (1): 

# 握手結束。
TLSv1.2 (IN), TLS handshake, Finished (20): 

# SSL 鏈接採用 ECDHE-RSA-AES256-GCM-SHA384 密碼套件。
# ECDHE 表示密鑰交換方法採用橢圓曲線迪菲-赫爾曼交換方法
# RSA 表示密鑰交換中使用的簽名方式
# AES-256-GCM 表示的是對稱加密算法
# SHA-384 表示的是內容完整性校驗使用的哈希算法
SSL connection using TLSv1.2 / ECDHE-RSA-AES256-GCM-SHA384 

# 以後的幾行包含了證書的內容,包括有效時間、經常使用名、證書籤發機構等。
Server certificate: 
      # Common Name 爲 ymfe.org
    subject: CN=ymfe.org
      # 在此時間以前無效
    start date: Aug 31 05:50:00 2017 GMT
      # 在此時間以後無效
    expire date: Nov 29 05:50:00 2017 GMT
      # 域名和證書的域名匹配
    subjectAltName: host "ymfe.org" matched cert's "ymfe.org"
      # 簽發者是 Let's Encrypt
    issuer: C=US; O=Let's Encrypt; CN=Let's Encrypt Authority X3

握手的詳細步驟

client_hello

這一步中,瀏覽器會向服務器發出創建 HTTPS 的請求,在請求中,瀏覽器會帶上一些創建鏈接的必要信息(注意:這一步的信息全都是明文的),包括:

  1. 版本。客戶端支持的最高的 TLS 協議版本從高到低依次爲:TLS v1.2, TLS v1.1, TLS v1.0, SSL v3, SSL v2。其中低於 TLS v1.0 的版本基本再也不使用,由於 SSL v3 和 SSL v2 都存在漏洞,Google 和 Mozilla 已明確禁用 SSL 協議。
  2. 密碼套件。按優先級降序排列的、客戶端支持的加密套件列表。每一個加密套件會各包含一個認證算法(用於身份驗證)、密鑰交換算法(用於協商密鑰)、對稱加密算法(用於消息加密)和信息摘要算法(用於完整性校驗)。
  3. 壓縮方法。客戶端支持的用於壓縮消息、下降傳輸體積的壓縮算法列表。
  4. 隨機數。一個由客戶端生成的隨機數,使用 32 位時間戳和一個安全隨機數生成器生成的 28 字節隨機數組成。這個隨機數用於後續 Master Key 的生成,並防止重放攻擊。
  5. 會話標識。一個變長的會話標誌。非 0 值意味着客戶端但願更新當前已存在的鏈接的參數或者爲此鏈接建立一個新的鏈接。0 值表示客戶端想在新會話上建立一個新鏈接。
  6. 擴展字段。包含一些其餘的相關參數(好比 SNI)。

server_hello

客戶端在發出 client_hello 消息以後,會等待服務器返回 server_hello 消息,包含和 client_hello 相同的參數。通常來講,參數結構以下:

  1. 版本。包含客戶端支持的最低版本和服務器支持的最高版本。
  2. 隨機數。由服務器生成的不一樣於客戶端在 client_hello 中發來的隨機數的另外一個獨立的隨機數。
  3. 會話標識。若是客戶端發送的會話標識不爲 0,服務器會使用與客戶端發送的一致的會話標識,不然返回的是服務器生成的一個新的會話標識。
  4. 密碼套件。包含了服務器從客戶端發來的密碼套件列表中選擇出的將要使用的密碼套件。
  5. 壓縮方法。包含了服務器從客戶端發來的壓縮方法列表中選擇出的將要使用的壓縮方法。

(certificate) (+ server_key_exchange) (+ certificate_request) + server_hello _done

一般來講,服務器會在 certificate 消息中發送其自身的證書供客戶端進行驗證,這個消息包含一個或一組 X. 509 證書。若是採用的是固定 Diffie-Hellman 方法(更多關於 Diffie-Hellman 的內容請查看維基百科上的詞條 Diffie-Hellman),此 certificate 消息將使用服務器 Diffie-Hellman 公鑰參數做爲服務器的密鑰交換消息。有一種密鑰交換方法——匿名 Diffie-Hellman 方法,不須要 certificate 消息。該算法使用基本的 Diffie-Hellman 算法,在向對方發送其 Diffie-Hellman 公鑰參數時,不進行認證(由於沒有認證,因此這種方法容易受到中間人攻擊)。

接着,除了兩種狀況:(1) 服務器發送了帶有固定 Diffie-Hellman 參數的證書;(2) 使用 RSA 密鑰交換;不須要發送 server_key_exchange 消息,其他狀況服務器均會發送 server_key_exchange 消息,用以向客戶端發送以後用以生成密鑰的各項參數。該消息的內容根據密鑰交換算法不一樣而不一樣,具體內容不在本文討論之列。該項參數做爲 server_key_exchange 消息的第一項值。

而後,服務器將對消息使用散列函數(根據不一樣簽名算法選擇不一樣的散列函數,例如 MD5 或者 SHA-1 等)對客戶端發來的隨機數、服務器生成的隨機數以及 server_key_exchange 消息中的各項參數進行求值並使用服務器的私鑰進行簽名。該值做爲 server_key_exchange 消息中的第二項值。

若是服務器須要驗證客戶端的身份(即雙向認證),則會發送 certificate_request 消息,請求客戶端發送其自身的證書。

最後,服務器發送 server_hello_done 消息,代表服務器的 hello 相關的消息結束。在發送此消息以後,服務器會等待客戶端應答,該消息沒有參數。

(certificate) + client_key_change (+ certificate_verify)

客戶端在收到服務器發來的 server_hello_done 消息以後,會驗證服務器提供的證書是否合法,並檢查 server_hello 的各項參數。若是驗證經過,則客戶端會向服務器發送一條或多條消息。

若是服務器發送了 certificate_request 消息,且客戶端有合適的證書,則客戶端會發送一條 certificate 消息,不然會發送一個「無證書警報」。

而後客戶端會發送 client_key_exchange 消息,其內容取決於密鑰交換的類型:

  1. RSA:客戶端生成 48 字節的 PreMaster Key,並使用服務器證書中的公鑰或者服務器密鑰交換消息中的臨時 RSA 密鑰加密。這個密鑰會被用於以後的 Master Key 的計算。
  2. 瞬時或匿名 Diffie-Hellman: 發送客戶端的 Diffie-Hellman 公鑰參數。
  3. 固定 Diffie-Hellman: 因爲證書消息中包括 Diffie-Hellman 公鑰參數,因此該消息爲空。

最後,若是客戶端具備證書且證書具有簽名能力(即除了帶固定 Diffie-Hellman 參數外的全部證書),能夠發送一個 certificate_verify 消息來提供對客戶端證書的精確認證。

change_cipher_spec + finished

通過以上步驟,客戶端和服務器已經能夠經過獲得的消息計算出 Master Key 了。從如今開始,客戶端和服務器都將開始使用協商好的加密算法、密鑰進行通訊,在正式傳遞消息以前會計算 Master Key 及 Master Key 和以前握手過程當中收到的全部信息的 hash,並經過協商好的加密算法使用 Master Key 加密,做爲 change_cipher_spec 消息的內容,接着發送 finished 消息。服務器在收到客戶端發來的 change_cipher_specfinished 消息以後,也會計算 Master Key 並使用協商好的加密算法和 Master Key 計算 Master Key 和以前握手過程當中收到的全部信息的 hash,發回給客戶端用以驗證。至此,握手階段結束,以後就能夠交換應用層的內容了。

如何加密應用層內容

細心的讀者可能發現,在創建鏈接的過程當中,交換的僅僅是密鑰而不是內容,爲何這麼複雜的過程僅僅交換了密鑰呢?

對稱加密和非對稱加密

經常使用的加密方式分爲兩種:

  • 對稱加密:加密和解密使用的是相同的密鑰。
  • 非對稱加密:加密和解密使用的不是相同的密鑰,而是一對密鑰對,分別稱爲公鑰私鑰

對稱加密最大的特色就是通訊雙方都須要知道加密密鑰,這對於互聯網上的服務器和客戶端來講,在事先沒有創建安全信道的狀況下安全地傳送密鑰幾乎是不可能的。不過相較於非對稱加密來講,對稱加密的優勢就是快。

非對稱加密最大的特色就是通訊雙方只須要知道密鑰對中的一個,並且使用公鑰加密的內容只能經過私鑰解密,使用私鑰加密的內容只能經過公鑰解密。對於一個實體來講,公鑰能夠公開給任何人,只須要保證自身的私鑰的安全,就能夠保證其與另外一個實體的通訊內容不會被第三者竊取。

HTTPS 用了哪一種加密方法?

在 HTTPS 中,對稱加密和非對稱加密都用到了。非對稱加密能夠在不安全的信道上傳遞祕密內容,可是因爲一般使用的非對稱加密方法相較於對稱加密算法慢不少,所以在 HTTPS 中僅使用非對稱加密算法交換對稱密鑰,交換密鑰以後的通訊內容均使用對稱加密算法加密和解密,這樣既能夠保證密鑰的安全也能夠保證內容的加解密速度,這對於移動端設備來講相當重要。

擴展閱讀

中間人攻擊

中間人攻擊(Man In The Middle Attack,簡稱 MITM),是指攻擊者與本來通訊的兩個實體分別創建通訊,並交換攻擊者所收到的數據,讓本來通訊的兩個實體誤覺得本身在一條加密的信道中和對方直接對話,但其實整個對話過程都直接受到攻擊者的控制,攻擊者能夠隨意增長、刪除、修改通訊的內容。通常來講,加密協議都會加入一些特殊的方法來實現通訊雙方的互相認證,以免中間人攻擊。好比 HTTPS 中就使用證書機制來防止中間人攻擊。

以前提到匿名 Diffie-Hellman 方法易受中間人攻擊,就是由於其不對祕密內容(即 Diffie-Hellman 公鑰參數)進行簽名認證致使的。在這個過程當中,服務器向客戶端發送的公鑰參數若是被攻擊者截獲並替換爲本身的公鑰參數,那麼攻擊者就能夠假裝成服務器和客戶端分別和客戶端和服務器進行對話,並且能夠徹底控制通訊的內容。

SNI

當進行 SSL/TLS 握手時,服務器會提供自身的證書給客戶端以供客戶端驗證。可是若是一臺服務器上託管了多個 HTTPS 站點,那麼服務器提供的證書可能就是錯誤的。而對於 SSL/TLS 握手鍊接來講,服務器名稱不匹配會致使客戶端斷開鏈接,由於服務器名稱不匹配代表可能有人正在進行中間人攻擊。

一張證書中包含多個主機名是能夠的,在以前提到的 curl -v -I -L https://ymfe.org 命令中出現了一個叫作 subjectAltName 的字段,這個字段就是用於指定多個域名的,在 common namesubjectAltName 中還可使用通配符。

一臺服務器託管多個站點是很是常見的。在被託管的站點中,它們多是同一個域名下的子域名,也可能徹底不是同一個域名。若是多個站點都用同一張證書的話,那麼服務器須要知道全部被託管的站點的域名,維護一個域名列表,這在不少狀況下是不切實際的。而若是爲每一個 HTTPS 服務器都分配一個獨立的 IP 的話,不但會增長成本,還會惡化 IPv4 地址的枯竭狀況。

基於名稱的虛擬主機可讓多個 DNS 主機名指向同一個服務器。在客戶端發起請求的時候,會在 HTTP 頭部添加正在請求的主機名稱,服務器根據這個主機名稱來提供不一樣的服務。而 HTTPS 中,在創建握手以前是不會發送任何 HTTP 頭部的,也就沒法獲取客戶端正在請求的主機名稱了。所以,沒法使用 HTTP 頭部來決定給客戶端提供哪張證書。

SNI(Server Name Indication,服務器名稱指示)是一個擴展的 TLS 協議。這個協議容許客戶端在創建 HTTPS 握手時告知服務器它正在鏈接的服務器的名稱。這就容許服務器根據客戶端在握手消息發來的服務器名稱來提供正確的 HTTPS 證書,避免由於證書錯誤致使握手失敗。

相關文章
相關標籤/搜索