讓你一文掌握 CA 證書
在互聯網環境中,數據安全是每個開發者和用戶都會關注的核心問題。HTTPS(HyperText Transfer Protocol Secure)是一種基于加密傳輸的網絡協議,是應用層保護通信安全、防止數據被竊聽和篡改的主要手段。
在很多一線企業,例如騰訊、阿里、字節等,許多應用強制要求使用 HTTPS 協議進行通信,Kubernetes 也提倡通過 HTTPS 協議進行通信。那么,為什么建議通過 HTTPS 協議而非 HTTP 協議?這源于二者的核心區別:
- HTTP 協議以明文方式傳輸數據,在網絡中傳輸時可能遭受竊聽、篡改或冒充攻擊,安全性較低,存在數據泄露風險;
- HTTPS 協議基于 HTTP 協議增加了 SSL 安全層,通過加密通道傳輸數據,安全性更高。
通常,HTTPS 協議主要實現以下兩類功能:
- 數據傳輸加密: 通過 HTTPS 傳輸的數據始終以加密形式存在,確保信息安全;
- 身份認證: HTTPS 支持單向認證和雙向認證。單向認證用于驗證服務端的真實性,雙向認證則同時驗證服務端和客戶端的合法性。
在實際的企業應用中,HTTPS 的使用方式主要包括:
- 利用 HTTPS 的數據加密能力,啟用單向認證驗證服務端的合法性,客戶端認證則采用其他方式,例如 Bearer 認證。miniblog 項目采用的正是這種方式;
- 利用 HTTPS 的數據加密能力,同時通過雙向認證驗證服務端和客戶端的合法性。
由于 CA 認證和 HTTPS 認證流程經常在面試中被考察,同時 miniblog 在啟用 HTTPS 服務時需要理解相關內容。接下來,本課程將對這兩部分進行詳細介紹。
一、什么是 HTTPS?
HTTPS 是 HTTP(超文本傳輸協議)的安全版本。它通過在 HTTP 和傳輸層之間加入 SSL/TLS(安全套接字層/傳輸層安全協議)來確保通信安全。相比 HTTP,HTTPS 增加了三項核心功能:
- 數據加密:通過加密技術,確保通信內容不會被第三方竊聽;
- 身份驗證:通過服務器證書驗證服務器身份,防止中間人攻擊;
校驗數據是否在傳輸過程中被篡改。
使用 HTTPS 后,數據從客戶端到服務器的整個過程都被加密保護,只有通信雙方才能解碼數據。
二、認識 CA 證書
CA 證書的內容較多,可以從以下四個方面掌握 CA 證書相關知識:
- CA 證書相關名詞;
- CA 證書簽發流程;
- CA 證書認證流程;
- CA 證書簽發實戰。
1. CA 證書相關名詞
CA 證書涉及眾多名詞,以下整理了一些核心名詞,供參考:
(1) CA: 數字證書認證機構(Certificate Authority,簡稱 CA),是負責發放和管理數字證書的權威機構,作為受信任的第三方,承擔公鑰體系中公鑰合法性檢驗的職責;
(2) CA 證書: CA 證書是由 CA 簽發的數字證書,其格式可能有所不同,目前最常使用的是 X.509 證書格式;
(3) 公鑰和私鑰: 公鑰(Public Key)和私鑰(Private Key)是一對密鑰,通過特定算法生成。公鑰是密鑰對中公開的部分,通常用于加密會話密鑰、驗證數字簽名或加密需通過相應私鑰解密的數據;私鑰則是非公開的部分;
(4) 加密算法: 可以使用多種加密算法對數據進行加密。常見的加密算法包括以下兩類:
(5) 對稱加密: 只有一個密鑰進行加密和解密,密鑰相同且加解密速度較快。典型的對稱加密算法包括 DES 和 AES 等;
(6) 密鑰以成對形式出現(公鑰和私鑰),公鑰和私鑰互為匹配,且無法通過公鑰推導出私鑰,反之亦然。公鑰用于加密時需通過私鑰解密,私鑰用于加密時需通過公鑰解密。與對稱加密相比,其速度較慢。典型非對稱加密算法包括 RSA 和 DSA 等。
(7) X.509 證書編碼格式: X.509 證書可能采用不同的編碼規則。目前編碼格式主要包括以下兩種:
- PEM(Privacy Enhanced Mail): 文本格式,文件后綴為 .pem,以 -----BEGIN XXXXXX----- 開頭,-----END XXXXXX----- 結尾,內容為 BASE64 編碼。多用于 Apache 和 UNIX 服務器;
- DER(Distinguished Encoding Rules): 二進制格式,文件后綴為 .der,不可讀。多用于 Java 和 Windows 服務器。
(8) X.509 證書文件后綴:X.509 證書的文件后綴不一定是 .pem 或 .der,以下是常見類型:
- CRT(.crt): 代表 Certificate,意為證書,常見于 UNIX 系統,可能采用 PEM 或 DER 編碼,大多數為 PEM 編碼;
- CER(.cer): 代表 Certificate,意為證書,常見于 Windows 系統,可能采用 PEM 或 DER 編碼,大多數為 DER 編碼;
- KEY(.key): 通常存放公鑰或私鑰,雖非 X.509 證書,但其編碼格式可能為 PEM 或 DER;
- CSR(.csr): Certificate Signing Request,即證書簽名請求。CSR 不是證書,而是向權威證書頒發機構申請簽名證書的請求,其主要包含一個公鑰及附加信息。在生成申請時,會同時生成一個私鑰,需自行妥善保管,無需提交給 CA 機構。
需要特別注意的是,如果證書文件的后綴是.pem 或.der,在文件名中應體現文件所屬類別,例如:server-key.pem 表示私鑰文件,server-crt.pem 表示證書文件。
為了更好地理解 CA 相關內容,接下來將以 CA 的簽發流程為主線,在介紹流程的同時,闡述相關概念,CA 的認證流程實際上也是 HTTPS 的認證流程。
2. CA 證書的簽發流程
CA 證書認證流程如下圖所示:
上圖所示的流程解釋如下:
(1) 服務端向第三方機構 CA 提交公鑰、組織信息、個人信息(如域名)等內容并申請認證(無需提交私鑰);
(2) CA 通過線上、線下等多種手段驗證申請者提供信息的真實性,例如確認組織是否存在、企業是否合法、是否擁有域名的所有權等;
(3) 如果信息審核通過,CA 會向申請者簽發認證文件(證書):
- 證書包含以下信息:申請者的公鑰、組織信息和個人信息、簽發機構 CA 的信息、證書有效期、證書序列號等明文信息,同時還包含一個簽名;
- 簽名的生成算法:首先,使用散列函數計算明文信息的信息摘要,然后,采用 CA 的私鑰對信息摘要進行加密,生成的密文即為簽名。
(4) 客戶端向服務端發出請求后,服務端返回服務端的證書文件;
(5) 客戶端讀取服務端證書中的明文信息,并使用相同的散列函數計算信息摘要。隨后,利用對應 CA 的公鑰解密簽名數據并對比信息摘要。如果兩者一致,則可以確認證書的合法性,即公鑰合法。同時,客戶端還需驗證證書中的域名信息、有效期等內容。客戶端通常內置信任 CA 的根證書(包含公鑰),如果 CA 不被信任,則無法找到對應 CA 的證書,該證書將被判定為非法;
(6) 客戶端生成一個隨機數 R,并用服務端證書中的公鑰加密后發送給服務端。服務端使用其私鑰解密獲取隨機數 R,隨后雙方使用對稱加密算法進行數據交換。
提示:證書由以下部分組成:公鑰(服務端生成的密鑰對中的公鑰)+申請者與頒發者信息+簽名(使用 CA 機構生成的密鑰對中的私鑰進行簽名)。頒發證書的過程實際上是 CA 使用其私鑰對證書請求文件進行簽名。
3. CA 認證流程
CA 證書的認證分為單向認證和雙向認證。在實際開發中,可根據需要自行選擇:
- 單向認證:適用于無需在通信層對用戶身份進行驗證的場景,一般在應用邏輯層保證用戶的合法登錄。單向認證也是企業應用中,使用最多的認證方式;
- 雙向認證:要求通信雙方相互驗證身份。例如,在企業應用服務之間存在互調關系時,可能需要對通信雙方進行身份驗證。
(1) 單向認證流程
單向認證流程如下圖所示。
上圖 已經清晰的展示了單向流程的步驟,這里不再詳解。需要注意的是第 3 步使用的是 CA 機構證書(根證書)的公鑰來解密簽名。
通過上述單向認證流程可以看出,整個流程需要以下三個證書文件:根證書、服務器端公鑰證書、服務器端私鑰文件。
(2) 雙向認證流程
單向認證僅驗證了服務端的身份。如果有人冒充客戶端,該如何應對?此時可以采用雙向認證。
雙向認證 SSL 握手過程與單向認證有所不同,其大部分步驟與單向認證過程相同。但在客戶端成功驗證服務器后,新增了服務器驗證客戶端的流程步驟。雙向認證流程如下圖所示。
通過上述雙向認證流程可以看出,整個雙向認證過程需要 5 個證書文件:根證書、服務器端公鑰證書、服務器端私鑰文件、客戶端公鑰證書、客戶端私鑰文件。
4. CA 證書簽發實戰
CA 證書由權威的 CA 機構簽發,其簽發流程較為復雜且費用較高。在后端應用開發中,通常由開發或運維人員自行生成根證書及其私鑰,并扮演 CA 的角色,負責為其他服務端和客戶端簽發證書,此類證書也稱為自簽證書。
在企業應用開發中,可以使用 openssl 工具來簽發根證書、服務端證書和客戶端證書。使用 openssl 工具簽發證書具體包括以下幾步:
- 簽發根證書和私鑰;
- 生成服務端證書;
- 生成客戶端證書;
(1) 步驟一:簽發根證書和私鑰
簽發根證書和私鑰包括以下 3 步操作:生成根證書私鑰、生成請求文件、生成根證書。
① 生成根證書****私鑰
使用以下命令生成根證書私鑰:
$ openssl genrsa -out ca.key 1024
genrsa 子命令主要用于生成 RSA 私鑰。命令行格式:openssl genrsa [args] [numbits]。涉及參數說明如下:
- -out file:將生成的私鑰保存至指定的文件中;
- numbits:指定生成私鑰的大小,默認是 2048。
② 生成請求文件
使用證書私鑰生成請求文件,命令如下:
$ openssl req -new -key ca.key -out ca.csr -subj "/C=CN/ST=Guangdong/L=Shenzhen/O=devops/OU=it/CN=127.0.0.1/emailAddress=colin404@foxmail.com"
req 子命令主要用于創建證書請求文件,其命令行格式為:openssl req [options] <infile> outfile。參數說明如下:
- -new:創建新的證書請求文件;
- -key file:指定創建證書請求所使用的私鑰文件;
- -out arg:指定輸出文件路徑;
- -subj arg:設置或修改證書請求中的主體信息。
證書請求的主體信息選項說明如下:
- CN(Common Name):指定證書中標識身份的名稱,該名稱必須唯一。通常填寫需要申請 SSL 證書的域名(domain)或子域名(subdomain);
- C(Country): 國家代碼;
- ST(State): 州或省;
- L(Locality): 城市;
- O(Organization): 組織名稱;
- OU(Organizational Unit): 組織單位名稱。
提示:不同證書的 CSR 文件,其 CN、C、ST、L、O、OU 的組合必須不同。在創建后續證書的 CSR 文件時,CN 必須各不相同,而 C、ST、L、O 和 OU 可以相同,以實現區分證書的目的。
③ 生成根證書
執行以下命令生成根證書:
$ openssl x509 -req -in ca.csr -signkey ca.key -out ca.crt
x509 命令主要用于創建和修改 x509 證書,其命令行格式如下:openssl x509 [options] <infile> outfile。參數說明如下:
- -in arg:指定輸入文件,默認為標準輸入;
- -out arg:指定輸出文件,默認為標準輸出;
- -req:指定輸入文件為證書請求;
- -signkey arg:指定用于自簽名的私鑰文件;
- -CA arg:設置 CA 文件,必須為 PEM 格式;
- -CAkey arg:設置 CA 私鑰文件,必須為 PEM 格式;
- -CAcreateserial:創建序列號文件。
(2) 步驟二:生成服務端證書
執行以下命令來生成服務端證書:
# 1. 生成服務端私鑰
$ openssl genrsa -out server.key 1024
# 2. 生成服務端公鑰
$ openssl rsa -in server.key -pubout -out server.pem
# 3. 生成服務端向 CA 申請簽名的 CSR
$ openssl req -new -key server.key -out server.csr -subj "/C=CN/ST=Guangdong/L=Shenzhen/O=serverdevops/OU=serverit/CN=127.0.0.1/emailAddress=nosbelm@qq.com"
# 4. 生成服務端帶有 CA 簽名的證書
$ openssl x509 -req -CA ca.crt -CAkey ca.key -CAcreateserial -in server.csr -out server.crt
上述命令中,rsa 子命令主要用于處理 RSA 公私鑰文件。命令行格式:openssl rsa [options] <infile> outfile。涉及參數說明如下:
- -in arg: 指定輸入文件;
- -pubout:指定輸出文件為公鑰,默認為私鑰;
- -out arg:指定輸出文件。
(3) 步驟三:生成客戶端證書
執行以下命令來生成客戶端證書:
# 1. 生成客戶端私鑰
$ openssl genrsa -out client.key 1024
# 2. 生成客戶端公鑰
$ openssl rsa -in client.key -pubout -out client.pem
# 3. 生成客戶端向 CA 申請簽名的 CSR
$ openssl req -new -key client.key -out client.csr -subj "/C=CN/ST=Guangdong/L=Shenzhen/O=clientdevops/OU=clientit/CN=127.0.0.1/emailAddress=nosbelm@qq.com"
# 4. 生成客戶端帶有 CA 簽名的證書
$ openssl x509 -req -CA ca.crt -CAkey ca.key -CAcreateserial -in client.csr -out client.crt