GoLang:你真的了解 HTTPS 嗎?
一直以來,在實驗室甚至整個公司特別強調(diào)“安全和隱私”,近半年,筆者在用 GoLang 開發(fā)智能邊緣計算設(shè)備的網(wǎng)絡(luò)通信項目時,常被要求務(wù)必重視“通信的安全和隱私”。期間,對接了多個合作方,有的要求“公網(wǎng)下要防止域名劫持”,有的要求“客戶端上報要帶‘證書’啊,更安全”,還有要求除了要用 HTTPS,還要在業(yè)務(wù)邏輯上再進行二次哈希、摘要、加密等等。由于筆者對 HTTPS 的認知也僅停留在 “HTTPS 比 HTTP 更安全”的層面上,在項目開發(fā)中遇到很多通信相關(guān)的問題經(jīng)常束手無策,因此沉下心來,認認真真學(xué)習(xí)了 HTTPS 并記錄成此文。
一、HTTPS 之靈魂三問
要說 HTTPS,搞 IT 的甚至是不搞 IT 的,都知道:“HTTPS 比 HTTP 安全”。因此但凡要開發(fā)涉及網(wǎng)絡(luò)傳輸?shù)捻椖繒r,得到的需求一定有:“要用 HTTPS”。
1. HTTPS 是什么?
維基百科對 HTTPS 的解釋是:
超文本傳輸安全協(xié)議(英語:HyperText Transfer Protocol Secure,縮寫:HTTPS;常稱為 HTTP over TLS、HTTP over SSL 或 HTTP Secure)是一種通過計算機網(wǎng)絡(luò)進行安全通信的傳輸協(xié)議。HTTPS 經(jīng)由 HTTP 進行通信,但利用 SSL/TLS 來加密數(shù)據(jù)包。HTTPS 開發(fā)的主要目的,是提供對網(wǎng)站服務(wù)器的身份認證,保護交換數(shù)據(jù)的隱私與完整性。這個協(xié)議由網(wǎng)景公司(Netscape)在 1994 年首次提出,隨后擴展到互聯(lián)網(wǎng)上。 |
抓重點:HTTPS=HTTP over SSL/TLS,也就是說,HTTPS 在傳輸層 TCP 和應(yīng)用層 HTTP 之間,多走了一層 SSL/TLS。
由此可見,TLS/SSL 是 HTTPS 的核心! 那么,這個TLS/SSL又是何方神圣呢?文章How to use SSL/TLS to Secure Your Communications: The Basics指出:
The SSL/TLS protocol functions between two layers of the OSI Presentation layer.The handshake and record layers operate over TCP/IP to encrypt data received directly from the Application layer.
SSL/TLS 協(xié)議作用在傳輸層和應(yīng)用層之間,對應(yīng)用層數(shù)據(jù)進行加密傳輸。 |
借用文中的圖,可以直觀感受到:SSL和TLS都是加密協(xié)議。SSL,全稱 Secure Socket Layer,在 1994 年由網(wǎng)景公司(Netscape)最早提出 1.0 版本;TLS,全稱 Transport Layer Security,則是 1999 年基于 SSL3.0 版本上改進而來的。官方建議棄用 SSL 而保留和采用 TLS,但是由于歷史原因,SSL 仍然存在,而且很多人已經(jīng)習(xí)慣 SSL 這個名詞,因此現(xiàn)在索性就叫成 SSL/TLS。
2. HTTPS 為什么?
肯定有不少同學(xué)不假思索:“當(dāng)然是 HTTP 不安全,HTTPS 安全,所以選擇 HTTPS 唄!”那么,HTTPS 比 HTTP“好”在哪里?
維基百科上對 HTTP 的解釋如下:
設(shè)計 HTTP 最初的目的是為了提供一種發(fā)布和接收 HTML 頁面的方法。
HTTP 的發(fā)展是由蒂姆·伯納斯-李于 1989 年在歐洲核子研究組織(CERN)所發(fā)起。HTTP 的標(biāo)準(zhǔn)制定由萬維網(wǎng)協(xié)會(World Wide Web Consortium,W3C)和互聯(lián)網(wǎng)工程任務(wù)組(Internet Engineering Task Force,IETF)進行協(xié)調(diào),最終發(fā)布了一系列的 RFC,其中最著名的是 1999 年 6 月公布的 RFC 2616,定義了 HTTP 協(xié)議中現(xiàn)今廣泛使用的一個版本——HTTP 1.1。 |
HTTP 協(xié)議是為了傳輸網(wǎng)頁超文本(文本、圖像、多媒體資源),以及規(guī)范客戶端和服務(wù)器端之間互相請求資源的方法的應(yīng)用層協(xié)議。在 1989 年最早推出了 HTTP 0.9 版本,而 1999 年公布的 HTTP 1.1 是到目前(2020 年)仍舊廣泛使用的版本。
但是這個 HTTP 1.1 版本存在一個很大的問題-明文傳輸(Plaintext/Clear Text),這個問題在互聯(lián)網(wǎng)時代的今天是致命的,一旦數(shù)據(jù)在公共網(wǎng)絡(luò)中被第三方截獲,其通信內(nèi)容輕而易舉地就被竊取了。
因此,HTTPS 應(yīng)運而生,它被公認的三大優(yōu)勢有:
- 數(shù)據(jù)加密,防竊聽
- 身份驗證,防冒充
- 完整性校驗,防篡改
啰嗦說一句:第 1 點確實是解決了 HTTP 明文傳輸;至于第 2 和第 3 點,其他一些應(yīng)用層協(xié)議也會遇到(服務(wù)端被冒充、數(shù)據(jù)被篡改是網(wǎng)絡(luò)傳輸中“較常見”的問題)。
再插一句題外話:2015 年推出的 HTTP 2 在 HTTP 1.1 的基礎(chǔ)上有很大改進,其中一點就是 HTTPS。
3. HTTPS 怎么做?
本文接下來將從 HTTPS 的 3 個優(yōu)勢展開說明,即:
- 數(shù)據(jù)加密,即 HTTPS 是怎么進行數(shù)據(jù)加密的。本章介紹 HTTPS 中的對稱加密和非對稱加密
- 身份驗證,即 HTTPS 是怎么讓客戶端相信“發(fā)給我數(shù)據(jù)的服務(wù)端是我想要的服務(wù)器”。本章介紹 HTTPS 的 CA 和證書
- 完整性校驗,即 HTTPS 是怎么做數(shù)據(jù)完整性校驗以防止被篡改。本章介紹 HTTPS 的哈希
最后,為了整篇文章的完整性,還會增加以下幾個內(nèi)容:
- HTTPS 流程,即客戶端和服務(wù)器端 HTTPS 通信全過程
- 實際問題,記錄了筆者在實戰(zhàn)中遇到 HTTPS 相關(guān)問題
二、數(shù)據(jù)加密:HTTPS 的對稱加密和非對稱加密
相信不少同學(xué)會說"對稱加密和非對稱加密有什么好講的?前者只有一把密鑰做加解密;后者有兩把密鑰,公鑰和私鑰,互為加解密,公鑰給對方,私鑰自己用。HTTPS 兩者都有。好了,這章可以結(jié)束啦。"
三個問題:
- HTTPS 為什么同時要有對稱加密和非堆成加密兩種加密方式?
- HTTPS 對稱加密的密鑰(本文稱為 SK,下同)如何產(chǎn)生和傳輸?
- HTTPS 的有幾套非對稱加密?目的是什么?是否可以省略?
好,一個問題一個問題來。
問題 1:HTTPS 為什么同時要有對稱加密和非對稱加密兩種加密方式?
默認各位同學(xué)已經(jīng)知曉對稱加密和非對稱加密(了解基本原理即可),不清楚的同學(xué)推薦閱讀知乎文章-《對稱加密與非對稱加密》,文章最后指出了這兩個加密方式的優(yōu)缺點,原文如下:
(1)對稱加密加密與解密使用的是同樣的密鑰,所以速度快,但由于需要將密鑰在網(wǎng)絡(luò)傳輸,所以安全性不高。
(2) 非對稱加密使用了一對密鑰,公鑰與私鑰,所以安全性高,但加密與解密速度慢。 |
那么解決辦法有嗎?有,文章隨后說道:
(3)解決的辦法是將對稱加密的密鑰使用非對稱加密的公鑰進行加密,然后發(fā)送出去,接收方使用私鑰進行解密得到對稱加密的密鑰,然后雙方可以使用對稱加密來進行溝通。 |
確實,HTTPS(最開始)就是這么做的!其思路大致如下:
- 首先一定要明確HTTPS既有對稱加密,又有非對稱加密。
- 由于對稱加密性能高速度快,因此在傳輸數(shù)據(jù)時(也就是對話內(nèi)容)采用對稱加密。
- 但是對稱加密的密鑰SK,既沒辦法預(yù)先設(shè)置(密鑰不可能只有一把,服務(wù)器端維護大量密鑰也不具備可行性),因此只能選擇在對話前通過網(wǎng)絡(luò)協(xié)商出一把新的SK。
- 為了確保SK的傳輸安全,使用非對稱加密來協(xié)商SK。
HTTPS 的這種設(shè)計同時兼顧了安全和效率,贊嘆先驅(qū)們的智慧!
問題 2:HTTPS 對稱加密的密鑰 SK 如何產(chǎn)生和傳輸?
通過第一個問題,我們知道了 HTTPS 分為2 個過程:
- 協(xié)商對稱加密密鑰 SK 的非對稱加密階段,稱為TLS 握手階段。
- 使用 SK 對數(shù)據(jù)(對話內(nèi)容)進行對稱加密的階段,稱為數(shù)據(jù)通信階段。
過程 2數(shù)據(jù)通信階段:發(fā)送端首先用密鑰 SK 對通信內(nèi)容進行對稱加密,接著通過網(wǎng)絡(luò)傳輸出去;對端收到數(shù)據(jù)后,用 SK 先將數(shù)據(jù)解密,于是就得到了通信內(nèi)容。這里筆者有一個問題尚未求證:在數(shù)據(jù)傳輸過程中,是否會對通信數(shù)據(jù)進行哈希以確保其不被篡改?姑且記一筆。
過程 1TLS 握手階段:協(xié)商密鑰 SK。網(wǎng)上關(guān)于這個知識點的文章有很多,然而一些已經(jīng)過時,一些則不全。就協(xié)商密鑰 SK 這塊,筆者推薦《掃盲 HTTPS 和 SSL/TLS 協(xié)議[3]:密鑰交換(密鑰協(xié)商)算法及其原理》和《密鑰協(xié)商機制》。本文直接扔出結(jié)論,HTTPS 協(xié)商對稱加密密鑰 SK 的辦法有很多種,介紹 3 種較為常見的辦法:
- 基于非對稱加密算法
- 基于專用密鑰交換算法,常見有 DH、ECDH 等
- 基于共享的 secret,常見有 PSK,SRP 等
(1) 方法 1:基于非對稱加密算法
維基百科對于非對稱加密算法的解釋:公開密鑰密碼學(xué)(英語:Public-key cryptography)也稱非對稱式密碼學(xué)(英語:Asymmetric cryptography)是密碼學(xué)的一種算法,它需要兩個密鑰,一個是公開密鑰,另一個是私有密鑰;一個用作加密,另一個則用作解密。使用其中一個密鑰把明文加密后所得的密文,只能用相對應(yīng)的另一個密鑰才能解密得到原本的明文;甚至連最初用來加密的密鑰也不能用作解密。由于加密和解密需要兩個不同的密鑰,故被稱為非對稱加密;不同于加密和解密都使用同一個密鑰的對稱加密。雖然兩個密鑰在數(shù)學(xué)上相關(guān),但如果知道了其中一個,并不能憑此計算出另外一個;因此其中一個可以公開,稱為公鑰,任意向外發(fā)布;不公開的密鑰為私鑰,必須由用戶自行嚴(yán)格秘密保管,絕不透過任何途徑向任何人提供,也不會透露給被信任的要通信的另一方。
非對稱加密 RSA 協(xié)商密鑰的辦法,是 HTTPS(嚴(yán)格說是 SSL/TLS 協(xié)議)最早的辦法,其過程如下:
- 客戶端給服務(wù)端發(fā)送請求;
- 服務(wù)端返回客戶端自己的公鑰 PuK;
- 客戶端產(chǎn)生本次對話的對稱密鑰 SK,并用 PuK 進行加密得到 SK_Enc 后傳給服務(wù)端;
- 服務(wù)端收到 SK_Enc 后用自己的私鑰 PrK 解密得到 SK;若成功,則返回客戶端 OK,否則終止對話.
- 接下來,客戶端和服務(wù)端的對話均用 SK 加密后傳輸。
(2) 方法 2:基于專用密鑰交換算法
方法 1 是被大部分人熟知的,但是存在一個問題:如果服務(wù)端的私鑰 PrK 泄露了,那么 HTTPS 所做的加密也就不安全了。
因此,就有了密鑰交換算法(有說法是 keyless 方法)。方法原理筆者沒有深究(數(shù)學(xué)功底有限,看到大量的公式證明還是會煩…),DH 和 ECDH 協(xié)商密鑰算法大致過程如下:
ECDH 算法中的 A 和 B,在有的材料中也被稱為PreMaster-Secret。最終協(xié)商得到的密鑰 SK 也被稱為Master Secret,也被稱為Session Key。
直接給出結(jié)論:ECDH 比 DH 算法更快,有說法是 10 倍;而且 ECDH 比 DH 更難破解,可行性更好。
(3) 方法 3:基于共享的 secret
這類做法就是在客戶端和服務(wù)端預(yù)設(shè)好對稱加密密鑰,握手階段只需要傳遞類似鑰匙 id 即可。代表算法有 PSK。
問題 3:HTTPS 的有幾套非對稱加密?目的是什么?是否可以省略?
直接給出答案:2 套非對稱加密。
第一套用于協(xié)商對稱加密密鑰 SK(問題 2 一直在討論的內(nèi)容);第二套用于數(shù)字證書簽名加密(接下來一章會詳細討論 CA 證書)。這兩者的區(qū)別是:前者是服務(wù)器端(如果是雙向驗證的話,客戶端也會有一套非對稱加密公私鑰)產(chǎn)生的。私鑰在服務(wù)端上;后者是 CA 機構(gòu)產(chǎn)生的,私鑰在 CA 機構(gòu)那邊。
并且,這 2 套都不可以省略。(這個說法略不嚴(yán)謹,但是在實際操作中,確實都不建議省略。)
三、身份驗證:HTTPS 的證書
筆者認為,對大部分程序員來說,工作中遇到的 HTTPS 相關(guān)問題,80%~90%都是跟證書相關(guān)的。因此,了解證書非常關(guān)鍵!
1. 證書是什么?
解釋這個問題之前,先看幾個關(guān)鍵詞:CA,CA 機構(gòu),數(shù)字證書,數(shù)字簽名,(證書)指紋,(CA)證書,HTTPS 證書,SSL/TLS 證書。
理一理上面這些關(guān)鍵詞之間的關(guān)系:
- CA,CA 機構(gòu):機構(gòu)/組織概念。
- 數(shù)字證書,(CA)證書,HTTPS 證書,SSL/TLS 證書:CA 簽發(fā)的數(shù)字證書。
- 數(shù)字簽名,(證書)指紋:CA 簽發(fā)的證書的內(nèi)容之一,一段加密的密文。
智庫百科對數(shù)字證書的解釋是:
數(shù)字證書也稱公開密鑰證書,是指用于電子信息活動中電子文件行為主體的驗證和證明,并可實現(xiàn)電子文件保密性和完整性的電子數(shù)據(jù)。數(shù)字證書是一個經(jīng)證書認證中心(Certification Authority,簡稱 CA)發(fā)行的文件。
數(shù)字證書包含有行為主體信息和證書認證機構(gòu)的數(shù)字簽名。數(shù)字簽名是指以電子形式存在,可依附在電子文件中用于辨識電子文件的簽署者及表示對該電子文件內(nèi)容負責(zé)所使用的電子數(shù)字標(biāo)識。 |
抓重點:數(shù)字證書用于主體身份驗證。
首先,數(shù)字證書=主體信息+數(shù)字簽名。
Windows 下,我們可以在 Chrome 瀏覽器上點擊地址欄的“鎖”標(biāo)記后會出現(xiàn)下拉框,接著點擊“證書”即可看到通過 HTTPS 訪問該服務(wù)器時的數(shù)字證書。具體操作如下:
- 證書“常規(guī)”頁面,是關(guān)于該證書的一個籠統(tǒng)介紹,包括簽發(fā)該證書的 CA 機構(gòu)、該證書綁定的域名(頒發(fā)給)、證書有效期。
- 證書“詳細信息”頁面,以鍵值對形式展示了這張證書的完整內(nèi)容。(后文將詳細介紹證書內(nèi)容)
- 證書的“證書路徑”,以層級結(jié)構(gòu)展示了從該證書綁定的域名一直到根證書的路徑,這就是證書鏈。(后文會展開介紹證書鏈)
看完了 Chrome 瀏覽器上的證書,在讓我們通過 Wireshark 抓包來來看看數(shù)字證書:
對比 Chrome 上看到的數(shù)字證書和 Wireshark 抓包得到的數(shù)字證書,可以看到兩者呈現(xiàn)的證書內(nèi)容是一致的。總結(jié)來看,一張完整的數(shù)字證書包括:
- 主體的必要信息:版本(version)、序列號(serialNumber)、簽名算法(signatureAlgorithm)、頒發(fā)者(issuer)、有效期(validity)、使用者(subject)、公鑰信息(subjectPublicKeyInfo)
- 主體的擴展信息(extension):如密鑰標(biāo)識符、證書策略等
- 數(shù)字簽名(signature),也稱指紋
抽象為下圖:
2. 為什么是數(shù)字證書呢?
HTTPS 已經(jīng)對通信數(shù)據(jù)進行了加密,為什么還要驗證身份?說好的“人與人之間最基本的信任呢?”
這還不是因為各路黑客、駭客們總是在制造各種攻擊嗎?(捂臉)其中一個大名鼎鼎的中間人攻擊(Man-In-The-Middle Attack,MITM 攻擊),簡單的講,“中間人”在客戶端和服務(wù)端都不知情的情況下,夾在雙方之間竊聽甚至篡改通信信息,過程見下圖(圖引自《HTTPS 中間人攻擊實踐(原理·實踐)》):
在 HTTPS 的握手階段,一端向?qū)Χ税l(fā)送請求,對端返回自己的公鑰;而一端未驗證對方的身份和公鑰,直接協(xié)商密鑰。“中間人”看到了這個漏洞,夾在中間截獲了對端的公鑰,替換成了自己的公鑰。正是這步“拿錯了公鑰”或者說“信錯了對端”,使得 HTTPS 為加密(密鑰協(xié)商的非對稱加密和通信數(shù)據(jù)的對稱加密)所做的努力全部泡湯。
可見,在 HTTPS 中,“確保對端身份正確”即“確保拿到的公鑰正確”,而在網(wǎng)絡(luò)通信中所謂的“身份”,一般指的是通信一端的域名、IP 地址甚至是Mac 地址。所以,數(shù)字證書同時包含了通信一端的身份信息和公鑰信息。
但是數(shù)字證書會在網(wǎng)絡(luò)中傳輸(由被要求驗證身份的一端通過網(wǎng)絡(luò)傳給另一端),這就意味著證書也可能會被竊取篡改。這個時候權(quán)威的 CA 機構(gòu)就出馬了,他想了個辦法:加了一個“防偽標(biāo)識”— 數(shù)字簽名。具體做法如下:
- signature = RSA(PriKey_CA, Hash(message))
這里啰嗦幾句:數(shù)字簽名生成過程是首先對原文作哈希,把一段不定長的文本映射成固定長度的字符空間,接著再用 CA 機構(gòu)的私鑰對這段定長字符做加密。大大提高了整體的運算效率。
3. 證書是怎么工作的?
要了解證書是怎么做“身份驗證”,即“防冒充”,得從 2 個角度來說明:
- 申請證書,即需要被驗證身份的一端,需要申請一份能夠驗證自己身份的證書
- 驗證證書,即需要驗證對方身份的一端,拿到證書后驗證對端的身份
請注意,這里有一個前提:這張證書必須是由權(quán)威 CA 機構(gòu)頒發(fā)的,且尚在有效期內(nèi);或者是一張信任的私人證書。
(1) 申請證書
CA 機構(gòu)和證書的分類本文不討論,這里我們討論正規(guī)權(quán)威 CA 機構(gòu)簽發(fā)的證書,至于是 DV、OV 還是 EV,只是安全強度問題,工作原理是一樣的。
總結(jié)申請證書的過程:用戶向 CA 機構(gòu)提交自己的信息(如域名)和公鑰(用戶自己生成的非對稱加密公鑰,用于 TLS 握手階段和另一端協(xié)商密鑰用),CA 機構(gòu)生成數(shù)字證書,如下圖:
(2) 驗證證書
收到對端發(fā)過來的證書,執(zhí)行證書申請的“逆過程”即可,總結(jié)如下圖:
接受證書的一端先對除數(shù)簽名的其他部分做一次相同的哈希算法(證書中指明了哈希算法),得到這段文本的哈希映射,記作 H1;獲取 CA 機構(gòu)的公鑰對數(shù)字簽名屬性做解碼,得到了 CA 機構(gòu)計算出的哈希映射,記作 H2。對比 H1 和 H2 兩個字符串是否嚴(yán)格相等,若是,代表該證書的信息未被篡改,證書有效;否則,證書內(nèi)容被篡改,證書無效。
若證書有效,接受端會再進行對端的身份校驗(驗證域名),若身份驗證通過,接收端會拿證書上的公鑰(也是對端自己生產(chǎn)的非對稱加密公鑰)加密接下來整個 TLS 握手階段的信息之后,發(fā)送給對端。
這個過程中有一個問題:CA 機構(gòu)的公鑰怎么獲取?
回答:提前內(nèi)置。
眾所周知,操作系統(tǒng)和瀏覽器在軟件安裝階段會在其特定目錄下放置一堆的證書。如 Windows 的根證書管理在 certmgr 下:
這些證書都有個特點:權(quán)威 CA 機構(gòu)發(fā)布的根證書(Root Certificate)。根證書有幾個特點:
- 沒有上層機構(gòu)再為其本身作數(shù)字簽名
- 證書上的公鑰即為 CA 機構(gòu)發(fā)布的公鑰
- 權(quán)威 CA 機構(gòu)的自簽證書
而這些根證書會跟很多軟件,包括操作系統(tǒng)、瀏覽器一起被安裝到用戶設(shè)備上。即使沒有被提前安裝好,這些根證書也可以在 CA 機構(gòu)的官網(wǎng)上獲取得到。
目前全球大型權(quán)威 CA 機構(gòu)有 Symantec、GeoTrust、Comodo 以及 RapidSSL 等,并且這些機構(gòu)頒發(fā)的 SSL 數(shù)字證書,在市場的占有率是非常的高。(節(jié)選自《SSL 證書頒發(fā)機構(gòu)有哪些》)
本地被內(nèi)置了這么多的根證書,那要怎么知道我這份證書應(yīng)該要用哪一個根證書來驗證呢?
回答:證書信任鏈。
在信任鏈上有 3 類證書:根證書,中介證書和用戶證書。根證書前文已有說明,用戶證書就是對端發(fā)過來的證書,或者說是用戶向權(quán)威 CA 機構(gòu)綁定了自己身份(主要指域名)和自己公鑰的證書。中介證書可以理解由權(quán)威 CA 機構(gòu)委派的代理機構(gòu)簽發(fā)的數(shù)字證書,推薦閱讀《What is an intermediate certificate?》。中介證書或者說是中介機構(gòu)的存在是為了保證根證書的密鑰的安全性。
細心的同學(xué)仔細看一看 certmgr 會發(fā)現(xiàn)有一個分類是“中間證書頒發(fā)機構(gòu)”,這里存放的就是中介證書。用戶證書絕大多數(shù)是通過權(quán)威的 CA 機構(gòu)的代理中介機構(gòu)頒發(fā)。
這么來說,根據(jù)對端發(fā)來的用戶證書尋找對應(yīng)的根證書豈不是更困難了?
自問自答:這是一個在樹形數(shù)據(jù)結(jié)構(gòu)中,從葉子節(jié)點搜索根節(jié)點的過程,直接一個最原始的深搜(DFS)不就可以了嘛?舉例說明,如下圖(引自Wikipedia-Chain of trust):
- 從用戶證書開始。
- 記“Issuer”字段的值為 i1,搜索本地證書,尋找由“Subject”為 i1 的證書。
- 若沒有找到,結(jié)束返回證書無效;否則,跳到步驟 4)。
- 判斷該證書的 Issuer 值是否等于 Subject 值。
- 若是,則該證書是根證書,結(jié)束返回該證書;否則跳到步驟 6)。
- 以該證書開始,跳轉(zhuǎn) 2)(繼續(xù)搜索)。
更多關(guān)于信任鏈的知識點,推薦閱讀《What is the SSL Certificate Chain?》
4. 證書怎么樣?
相信不少同學(xué)或多或少接觸過證書文件,比如.pem、.crt、.cer、.key 等,于是問題就來了:
“為什么有這么多不同后綴名的證書啊?他們有什么聯(lián)系和區(qū)別?”
回答這個問題要從 3 個層面來分析:
- 證書標(biāo)準(zhǔn)
- 證書編碼格式
- 文件擴展名
(1) 證書標(biāo)準(zhǔn)
數(shù)字證書的格式普遍采用的是 X.509 國際標(biāo)準(zhǔn),維基百科對于 X.509 解釋如下:
X.509 是密碼學(xué)里公鑰證書的格式標(biāo)準(zhǔn)。X.509 證書已應(yīng)用在包括 TLS/SSL 在內(nèi)的眾多網(wǎng)絡(luò)協(xié)議里,同時它也用在很多非在線應(yīng)用場景里,比如電子簽名服務(wù)。X.509 證書里含有公鑰、身份信息(比如網(wǎng)絡(luò)主機名,組織的名稱或個體名稱等)和簽名信息(可以是證書簽發(fā)機構(gòu) CA 的簽名,也可以是自簽名)。對于一份經(jīng)由可信的證書簽發(fā)機構(gòu)簽名或者可以通過其它方式驗證的證書,證書的擁有者就可以用證書及相應(yīng)的私鑰來創(chuàng)建安全的通信,對文檔進行數(shù)字簽名。
X.509 是 ITU-T 標(biāo)準(zhǔn)化部門基于他們之前的 ASN.1 定義的一套證書標(biāo)準(zhǔn)。 |
(2) 證書的編碼格式
X.509 標(biāo)準(zhǔn)的證書文件具有不同的編碼格式:PEM 和 DER。
- PEM:
PEM,全稱 Privacy Enhanced Mail,以文本格式存儲,以 -----BEGIN
XXX-----開頭、-----END XXX-----結(jié)尾,中間內(nèi)容是 BASE64 編碼數(shù)據(jù)。其文本內(nèi)容大概如下:
- html -----BEGIN CERTIFICATE----- Base64編碼過的證書數(shù)據(jù) -----END CERTIFICATE-----
通常,PEM 格式可以存儲公鑰、私鑰、證書簽名請求等數(shù)據(jù)。查看 PEM 格式證書的信息一般采用如下命令:
- openssl x509 -in xxx.pem -text -noout
Apache 和 Nginx 服務(wù)器偏向于使用這種編碼格式。
- DER:
DER,全稱 Distinguished Encoding Rules,以二進制存儲,因此文件結(jié)構(gòu)無法直接預(yù)覽,只能通過如下命令查看:
- html openssl x509 -in xxx.der -inform der -text -noout
DER 格式也可以存儲公鑰、私鑰、證書簽名請求等數(shù)據(jù)。Java 和 Windows 應(yīng)用偏向于使用這種編碼格式。
當(dāng)然同一 X.509 證書的不同編碼之間可以互相轉(zhuǎn)換:
- PEM 轉(zhuǎn)為 DER:
- openssl x509 -in xxx.pem -outform der -out xxx.der
- openssl x509 -in xxx.der -inform der -outform pem -out xxx.pem
(3) 文件擴展名
不同的擴展名可以分為以下幾類:
- 證書:存放數(shù)字證書,X.509 標(biāo)準(zhǔn),格式可能是 PEM 或 DER。.crt、.cer
- 密鑰:用來存放一個 RSA 公鑰或私鑰,這類文件不是 X.509 標(biāo)準(zhǔn),但是是 PEM 或 DER 格式。后綴名有.key。
- 證書+密鑰:可同時存放證書和 RSA 公鑰/.pem、.der、.p12
- 證書請求:并不是證書,而是證書簽名請求。csr
四、完整性校驗:HTTPS 的哈希
哈希,鍵值對數(shù)據(jù)結(jié)構(gòu),通過哈希函數(shù)把一個空間映射到另一個空間。非常好用的一個工具,而且哪哪兒都有它的影子,比如負載均衡的一致性哈希、密碼學(xué)中用于信息加密或數(shù)據(jù)校驗的各種哈希(SHA、MD5 等)、二維空間定位的 GeoHash、對象相似度的 SimHash 等等。
HTTPS 的的哈希一共用在 2 個地方:
1. 證書的數(shù)字簽名
具體做法在上文證書一章節(jié)已經(jīng)說過,不再贅述。在這里使用哈希的目的主要是為了減少非對稱加密算法 RSA 在長文本上的開銷。
2. 對稱加密的 Message Digest
在數(shù)據(jù)通信階段,SSL/TLS 會對原始消息(message)做一次哈希,得到該消息 message 的摘要,稱為消息摘要(Message Digest)。對端接受到消息后,使用協(xié)商出來的對稱加密密鑰解密數(shù)據(jù)包,得到原始消息 message;接著也做一次相同的哈希算法得到摘要,對比發(fā)送過來的消息摘要和計算出的消息摘要是否一致,可以判斷通信數(shù)據(jù)是否被篡改。
五、HTTPS 通信流程
到此,HTTPS 涉及到的關(guān)鍵問題基本都覆蓋了。本章總結(jié)整個 HTTPS 的通信過程:
補充說明幾點:
1. 協(xié)商密鑰:客戶端/服務(wù)端隨機數(shù)、Client/Server Key
在加密一章節(jié)介紹的 ECDH 是停留在原理層面,實際中密鑰協(xié)商除了 PreMaster-Secret(即 Client/Server Key)之外,還有客戶端和服務(wù)端隨機數(shù)參與,參考文章《Https:TLS 握手協(xié)議》,引用文中的圖來自展示實際 ECDH 秘鑰協(xié)商的做法:
2. Change Cipher Spec
Change Cipher Spec是通知對方需要加密參數(shù)。文章《TLSde 改變密碼標(biāo)準(zhǔn)協(xié)議(Change Cipher Spec Protocol)》指出:
SSL 修改密文協(xié)議的設(shè)計目的是為了保障 SSL 傳輸過程的安全性,因為 SSL 協(xié)議要求客戶端或服務(wù)器端每隔一段時間必須改變其加解密參數(shù)。當(dāng)某一方要改變其加解密參數(shù)時,就發(fā)送一個簡單的消息通知對方下一個要傳送的數(shù)據(jù)將采用新的加解密參數(shù),也就是要求對方改變原來的安全參數(shù)。 |
SSL 修改密文協(xié)議是使用 SSL 記錄協(xié)議服務(wù)的 SSL 高層協(xié)議的 3 個特定協(xié)議之一,也是其中最簡單的一個。協(xié)議由單個消息組成,該消息只包含一個值為 1 的單個字節(jié)。該消息的唯一作用就是使未決狀態(tài)復(fù)制為當(dāng)前狀態(tài),更新用于當(dāng)前連接的密碼組。為了保障 SSL 傳輸過程的安全性,雙方應(yīng)該每隔一段時間改變加密規(guī)范。
3. Encrypted Handshake Message
Encrypted Handshake Message作用就是確認協(xié)商出來的對稱加密密鑰 SK 的正確性,在客戶端和服務(wù)端協(xié)商得到對稱加密密鑰 SK 之后,互相給對方發(fā)了一條用 SK 加密的消息,如果這個加密的消息被解密校驗成功,那么就說明對稱加密密鑰 SK 是正確的。
4. 單向驗證和雙向驗證
本章全部所探討的案例都是基于單向驗證,即客戶端向服務(wù)端請求證書、驗證服務(wù)端身份。在一些實際場景中,對安全性的要求更高,有服務(wù)端要求驗證客戶端的身份,即雙向驗證。雙向驗證在單向驗證基礎(chǔ)上,增加“在服務(wù)端發(fā)送證書之后,向客戶端發(fā)送‘請求證書’請求,接著驗證客戶端身份”這個步驟。參考下圖(圖片出處不查):
六、HTTPS 實戰(zhàn)問題記錄
1. 問題:HTTPS 是否需要做域名劫持?
沒必要。
原因如下:https 在證書校驗這步,客戶端除了通過對比數(shù)字簽名來校驗證書的有效性,還會比較證書上的域名是否與自己要訪問的域名一致。因此,只要服務(wù)器的證書是可信的且客戶端不跳過“證書驗證”這個步驟,https 能夠防止域名劫持。
筆者在實際中做過防止域名劫持的工作,具體做法是:首先,客戶端向可信賴的域名服務(wù)器請求域名對應(yīng)的 IP 地址;接著,客戶端用 IP 替換域名進行網(wǎng)絡(luò)請求。被稱為HTTPS 的 IP 直連。但在實際中會遇到了一個問題:域名身份不對。根本解決方案是:1).書校驗時,選擇自己定義的 hostname 進行校驗;2).證書校驗前,把 URL 的 IP 替換回域名。在很多語言實現(xiàn)中,解決方案更為簡單:在請求頭部的增加 host-name 字段,值填入域名即可。
2. 問題:"x509: certificate signed by unknown authority"
這個問題是客戶端拿到了服務(wù)器的證書要進行身份驗證,但是通過證書信任鏈策略發(fā)現(xiàn)中間斷了,搜索不到根證書。說白了就是客戶端本地沒有簽發(fā)這個用戶證書的根證書或中介證書。
實際中的解決辦法有:1). 缺啥裝啥,沒有根證書/中介證書,那就安裝上;2).跳過證書身份驗證這步。GoLang 中跳過身份驗證的實現(xiàn):
- client := &http.Client{
- Transport: &http.Transport{
- TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
- }
- }
3. 問題:https 項目中,服務(wù)端怎么管理證書和 RSA 密鑰?
看情況。
如果是正規(guī)的公司,一般會有統(tǒng)一的接入層幫忙做掉,后臺開發(fā)程序員只需要關(guān)心自己的業(yè)務(wù)邏輯即可。運維同事或者是負責(zé)接入層開發(fā)的同事們會定期更新證書,負責(zé)幫忙做 HTTPS 的 RSA 管理。而且這些證書都是由正規(guī)權(quán)威 CA 機構(gòu)簽發(fā)的,普遍的客戶端設(shè)備上都預(yù)置了對應(yīng)的根證書。
如果是個人,一般沒有條件負擔(dān) HTTPS 證書費用,因此可以選擇自己簽發(fā)自簽證書,或者到免費的證書簽發(fā)機構(gòu)申請證書。但是這類證書要求在客戶端上同步安裝對應(yīng)的根證書。
4. 問題:https 項目中,客戶端的根證書要提前安裝嗎?
上一個問題中已經(jīng)提到了:
- 如果是正規(guī)權(quán)威 CA 機構(gòu)簽發(fā)的證書,一般不需要提前安裝;
- 如果是私人簽發(fā)的證書,需要提前安裝。
但是,筆者在邊緣計算設(shè)備上開發(fā)時發(fā)現(xiàn),比如攝像頭這類的“tinny os”上,是一個“閹割”版本的 Linux 系統(tǒng),因此沒有安裝任何根證書。在這類設(shè)備上做 https 通信,一定需要提前安裝根證書才行。