细说 CA 和证书
CA,Catificate Authority,它的作用就是提供證書(即服務器證書,由域名、公司信息、序列號和簽名信息組成)加強服務端和客戶端之間信息交互的安全性,以及證書運維相關服務。任何個體/組織都可以扮演 CA 的角色,只不過難以得到客戶端的信任,能夠受瀏覽器默認信任的 CA 大廠商有很多,其中 TOP5 是 Symantec、Comodo、Godaddy、GolbalSign 和 Digicert。
服務器證書分類
可以通過兩個維度來分類,一個是商業角度,一個是業務角度。
| 支持 | 不支持 | ||
| 支持 | |||
| 支持 | 不支持 | ||
| www.barretlee.com | www.barretlee.com www.xiaohuzige.com www.barret.cc | *.barretlee.com | *.barretlee.com *.xiaohuzige.com *.barret.cc |
需要強調的是,不論是 DV、OV 還是 EV 證書,其加密效果都是一樣的!?它們的區別在于:
- DV(Domain Validation),面向個體用戶,安全體系相對較弱,驗證方式就是向 whois 信息中的郵箱發送郵件,按照郵件內容進行驗證即可通過;
- OV(Organization Validation),面向企業用戶,證書在 DV 證書驗證的基礎上,還需要公司的授權,CA 通過撥打信息庫中公司的電話來確認;
- EV(Extended Validation),打開 Github 的網頁,你會看到 URL 地址欄展示了注冊公司的信息,這會讓用戶產生更大的信任,這類證書的申請除了以上兩個確認外,還需要公司提供金融機構的開戶許可證,要求十分嚴格。
OV 和 EV 證書相當昂貴,使用方可以為這些頒發出來的證書買保險,一旦 CA 提供的證書出現問題,一張證書的賠償金可以達到 100w 刀以上。
CA 的作用
前文?HTTPS證書生成原理和部署細節?提到如果本地生成公/私鑰對和對應未簽證的證書,如果使用的證書沒有簽證,或者未在瀏覽器受信的 CA 簽證,你會看到下圖的問題:
上圖出現的錯誤是?net:ERR_CERT_AUTHORITY_INVALID,我們生成證書和公/私鑰對的流程都是正確的,但是瀏覽器不認這張證書,并且提示證書授權不通過;如果通過其他與 Common Name 不同的域名去訪問,如我注冊的時候使用的?localhost,但是訪問的時候用的?127.0.0.1,還會報出這樣的錯誤:
錯誤碼為?net:ERR_CERT_COMMON_NAME_INVALID,意思是 Common Name 不匹配,具體校驗流程可以在瀏覽器的 DevTools 中看到:
從上面幾張圖,可以大致了解 CA 和證書會做哪些事情,證書由域名、公司信息、序列號和簽名信息組成,當我們通過 HTTPS 訪問頁面時,瀏覽器會主動驗證證書信息是否匹配,也會驗證證書是否有效。
CA 有權給所有的域名簽發證書,如它可以私自給我的網站簽發一張?www.barretlee.com的證書,并且可以拿著新證書攔截網頁流量(當然,前提是這個 CA 是瀏覽器認證的權威 CA),那我的網站可能就很不安全了,對擁新證書的人來說,我的網站等同于在 HTTP 下進行通訊。
評估 CA 供應商
CA 供應商很多,提供服務的側重點可能也存在一些差異,比如很多 CA 都沒有提供證書吊銷的服務,這一點對于安全性要求很高的企業來說是完全不能接受的,那么對 CA 供應商的評估需要注意寫什么呢?
1. 內置根
所謂內置根,就是 CA 的根證書內置到各種通用的系統/瀏覽器中,只有根證書的兼容性夠強,它所能覆蓋的瀏覽器才會越多。
2. 安全體系
兩個指標可以判斷 CA 供應商是否靠譜,一是看價格,價格高自然有它的理由,必然提供了全套的安全保障體系;二是看黑歷史,該 CA 供應商有沒有爆出過什么漏洞,比如之前的 DigiNotar,被伊朗入侵,簽發了 500 多張未授權的證書,結果直接被各系統/瀏覽器將其根拉入黑名單,毫無疑問公司直接倒閉。
3. 核心功能和擴展功能
這就需要從業務上考慮了,不同的規模的企業、不同的業務對證書的要求不一樣,比如證書是否會考慮無 SNI 支持的瀏覽器問題,是否支持在 reissue 的時候添加域名,是否支持 CAA,是否支持短周期證書等等。
4. 價格
企業完全沒必要購買 Github 那樣的 EV 證書,太昂貴,而且一般的企業也未必能夠申請到這樣的證書。供應商很大,價格可以好好評估下,不一定要最貴,最適合的就行。
自建 Root CA
OpenSSL 是一個免費開源的庫,它提供了構建數字證書的命令行工具,其中一些可以用來自建 Root CA。
很多網站都希望用戶知道他們建立的網絡通道是安全的,所以會想 CA 機構購買證書來驗證 domain,所以我們也可以在很多 HTTPS 的網頁地址欄看到一把小綠鎖。
然而在一些情況下,我們沒必要去 CA 機構購買證書,比如在內網的測試環境中,為了驗證 HTTPS 下的一些問題,我們不需要部署昂貴的證書,這個時候自建 Root CA,給自己頒發證書就顯得很有價值了。
本節內容較多,主要是代碼演示生成證書和驗證的過程,可以跳過看下一節,直接看?這里:
- git clone //github.com/barretlee/autocreate-ca.git
- 依次執行?install-rootCA.sh、install-intermediateCA.sh?和?install-websiteConfig.sh
首先找到一個放置證書的文件夾,比如?/root/ca?下,下方的測試也在改目錄下,如果你要更換其他目錄,記得替換下文中的目錄地址。
創建 root pair
扮演 CA 角色,就意味著要管理大量的 pair 對,而原始的一對 pair 對叫做 root pair,它包含了 root key(ca.key.pen)和 root certificate(ca.cert.pem)。通常情況下,root CA 不會直接為服務器或者客戶端簽證,它們會先為自己生成幾個中間 CA(intermediate CAs),這幾個中間 CA 作為 root CA 的代表為服務器和客戶端簽證。
注意:一定要在絕對安全的環境下創建 root pair,可以斷開網絡、拔掉網線和網卡,當然,如果是測試玩一玩就不用這么認真了。
設定文件夾結構,并且配置好 openssl 設置:
$ cd /root/ca $ mkdir certs crl newcerts private $ chmod 700 private $ touch index.txt $ echo 1000 > serial $ wget -O /root/ca/openssl.cnf \ //raw.githubusercontent.com/barretlee/autocreate-ca/master/cnf/root-ca創建 root key,密碼可為空,設定權限為只可讀:
$ cd /root/ca $ openssl genrsa -aes256 -out private/ca.key.pem 4096Enter pass phrase for ca.key.pem: secretpassword Verifying - Enter pass phrase for ca.key.pem: secretpassword$ chmod 400 private/ca.key.pem創建 root cert,權限設置為可讀:
$ cd /root/ca $ openssl req -config openssl.cnf \-key private/ca.key.pem \-new -x509 -days 7300 -sha256 -extensions v3_ca \-out certs/ca.cert.pemEnter pass phrase for ca.key.pem: secretpassword You are about to be asked to enter information that will be incorporated into your certificate request. ----- Country Name (2 letter code) [XX]:CN State or Province Name []:Zhejiang Locality Name []: Organization Name []:Barret Lee Organizational Unit Name []:Barret Lee Certificate Authority Common Name []:Barret Lee Root CA Email Address []:$ chmod 444 certs/ca.cert.pem驗證證書:
$ openssl x509 -noout -text -in certs/ca.cert.pem正確的輸出應該是這樣的:
Certificate:Data:Version: 3 (0x2)Serial Number:87:e8:c0:a0:4b:e2:12:5dSignature Algorithm: sha256WithRSAEncryptionIssuer: C=CN, ST=Zhejiang, O=Barret Lee, OU=Barret Lee Certificate Authority, CN=Barret Lee Root CAValidityNot Before: Apr 23 05:46:36 2016 GMTNot After : Apr 18 05:46:36 2036 GMTSubject: C=CN, ST=Zhejiang, O=Barret Lee, OU=Barret Lee Certificate Authority, CN=Barret Lee Root CASubject Public Key Info:Public Key Algorithm: rsaEncryptionRSA Public Key: (4096 bit)Modulus (4096 bit):// ...Exponent: 65537 (0x10001)X509v3 extensions:X509v3 Subject Key Identifier:E5:2D:B8:2B:DC:88:FE:CE:DA:93:D8:6F:2E:74:04:D2:39:E7:C8:03X509v3 Authority Key Identifier:keyid:E5:2D:B8:2B:DC:88:FE:CE:DA:93:D8:6F:2E:74:04:D2:39:E7:C8:03X509v3 Basic Constraints: criticalCA:TRUEX509v3 Key Usage: criticalDigital Signature, Certificate Sign, CRL SignSignature Algorithm: sha256WithRSAEncryption// ...包含:
- 數字簽名(Signature Algorithm)
- 有效時間(Validity)
- 主體(Issuer)
- 公鑰(Public Key)
- X509v3 擴展,openssl config 中配置了 v3_ca,所以會生成此項
創建 intermediate pair
目前我們已經擁有了 Root Pair,事實上已經可以用于證書的發放了,但是由于根證書很干凈,特別容易被污染,所以我們需要創建中間 pair 作為 root pair 的代理,生成過程同上,只是細節略微不一樣。
生成目錄結構和 openssl 的配置,這里的配置是針對 intermediate pair 的:
$ mkdir /root/ca/intermediate $ cd /root/ca/intermediate $ mkdir certs crl csr newcerts private $ chmod 700 private $ touch index.txt $ echo 1000 > serial $ echo 1000 > /root/ca/intermediate/crlnumber $ wget -O /root/ca/openssl.cnf \//raw.githubusercontent.com/barretlee/autocreate-ca/master/cnf/intermediate-ca創建 intermediate key,密碼可為空,設定權限為只可讀:
$ cd /root/ca $ openssl genrsa -aes256 \-out intermediate/private/intermediate.key.pem 4096Enter pass phrase for intermediate.key.pem: secretpassword Verifying - Enter pass phrase for intermediate.key.pem: secretpassword$ chmod 400 intermediate/private/intermediate.key.pem創建 intermediate cert,設定權限為只可讀,這里需要特別注意的一點是?Common Name 不要與 root pair 的一樣?:
$ cd /root/ca $ openssl req -config intermediate/openssl.cnf -new -sha256 \-key intermediate/private/intermediate.key.pem \-out intermediate/csr/intermediate.csr.pemEnter pass phrase for intermediate.key.pem: secretpassword You are about to be asked to enter information that will be incorporated into your certificate request. ----- Country Name (2 letter code) [XX]:CN State or Province Name []:Zhejiang Locality Name []: Organization Name []:Barret Lee Organizational Unit Name []:Barret Lee Certificate Authority Common Name []:Barret Lee Intermediate CA Email Address []:使用?v3_intermediate_ca?擴展簽名,密碼可為空,中間 pair 的有效時間一定要為 root pair 的子集:
$ cd /root/ca $ openssl ca -config openssl.cnf -extensions v3_intermediate_ca \-days 3650 -notext -md sha256 \-in intermediate/csr/intermediate.csr.pem \-out intermediate/certs/intermediate.cert.pemEnter pass phrase for ca.key.pem: secretpassword Sign the certificate? [y/n]: y$ chmod 444 intermediate/certs/intermediate.cert.pem此時 root 的?index.txt?中將會多出這么一條記錄:
V 260421055318Z 1000 unknown .../CN=Barret Lee Intermediate CA驗證中間 pair 的正確性:
$ openssl x509 -noout -text \-in intermediate/certs/intermediate.cert.pem $ openssl verify -CAfile certs/ca.cert.pem \intermediate/certs/intermediate.cert.pemintermediate.cert.pem: OK瀏覽器在驗證中間證書的時候,同時也會去驗證它的上一級證書是否靠譜,創建證書鏈,將 root cert 和 intermediate cert 合并到一起,可以讓瀏覽器一并驗證:
$ cat intermediate/certs/intermediate.cert.pem \certs/ca.cert.pem > intermediate/certs/ca-chain.cert.pem $ chmod 444 intermediate/certs/ca-chain.cert.pem創建服務器/客戶端證書
終于到了這一步,生成我們服務器上需要部署的內容,上面已經解釋了為啥需要創建中間證書。root pair 和 intermediate pair 使用的都是 4096 位的加密方式,一般情況下服務器/客戶端證書的過期時間為一年,所以可以安全地使用 2048 位的加密方式。
$ cd /root/ca $ openssl genrsa -aes256 \-out intermediate/private/www.barretlee.com.key.pem 2048 $ chmod 400 intermediate/private/www.barretlee.com.key.pem創建?www.barretlee.com?的證書:
$ cd /root/ca $ openssl req -config intermediate/openssl.cnf \-key intermediate/private/www.barretlee.com.key.pem \-new -sha256 -out intermediate/csr/www.barretlee.com.csr.pemEnter pass phrase for www.barretlee.com.key.pem: secretpassword You are about to be asked to enter information that will be incorporated into your certificate request. ----- Country Name (2 letter code) [XX]:CN State or Province Name []:Zhejiang Locality Name []:Hangzhou Organization Name []:Barret Lee Organizational Unit Name []:Barret Lee's Personal Website Common Name []:www.barretlee.com Email Address []:barret.china@gmail.com使用 intermediate pair 簽證上面證書:
$ cd /root/ca $ openssl ca -config intermediate/openssl.cnf \-extensions server_cert -days 375 -notext -md sha256 \-in intermediate/csr/www.barretlee.com.csr.pem \-out intermediate/certs/www.barretlee.com.cert.pem $ chmod 444 intermediate/certs/www.barretlee.com.cert.pem可以看到?/root/ca/intermediate/index.txt?中多了一條記錄:
V 170503055941Z 1000 unknown .../emailAddress=barret.china@gmail.com驗證證書:
$ openssl x509 -noout -text \-in intermediate/certs/www.barretlee.com.cert.pem $ openssl verify -CAfile intermediate/certs/ca-chain.cert.pem \intermediate/certs/www.barretlee.com.cert.pemwww.barretlee.com.cert.pem: OK此時我們已經拿到了幾個用于部署的文件:
- ca-chain.cert.pem
- www.barretlee.com.key.pem
- www.barretlee.com.cert.pem
添加信任 CA 和證書的調試
雙擊?/root/ca/intermediate/certs/ca-chain.cert.pem?將證書安裝到系統中,目的是讓本機信任這個 CA,將其當作一個權威 CA,安裝?root pem?或者?intermediate chain pem?都是可以的,它們都具備驗證能力。如果不執行這一步,瀏覽器依然會提示?net:ERR_CERT_AUTHORITY_INVALID。
上面申請測試證書時,我設置的 Common Name 為?www.barretlee.com,由于不在線上機器測試,可以將其添加到 hosts:
127.0.0.1 www.barretlee.com執行下方測試代碼:
// https-server.js var https = require('https'); var fs = require('fs');var options = {key: fs.readFileSync('/root/ca/intermediate/private/www.barretlee.com.key.pem'),cert: fs.readFileSync('/root/ca/intermediate/certs/www.barretlee.com.cert.pem'),passphrase: 'passoword' // 如果生成證書的時候設置了密碼,請添加改參數和密碼 };https.createServer(options, function(req, res) {res.writeHead(200);res.end('hello world'); }).listen(8000, function(){console.log('Open URL: //www.barretlee.com:8000'); });可以看到這樣的效果:
查看證書的詳細信息:
?
回到最初的問題:
然而在一些情況下,我們沒必要去 CA 機構購買證書,比如在內網的測試環境中,為了驗證 HTTPS 下的一些問題,我們不需要部署昂貴的證書,這個時候自建 Root CA,給自己頒發證書就顯得很有價值了。
一般公司內網的電腦都會強制安裝一些安全證書,此時就可以把我們自建自簽名的證書導入/引導安裝到用戶的電腦中啦~
無 SNI 支持問題
很多公司由于業務眾多,域名也是相當多的,為了方便運維,會讓很多域名指向同樣的 ip,然后統一將流量/請求分發到后端,此時就會面臨一個問題:由于 TLS/SSL 在 HTTP 層之下,客戶端和服務器握手的時候還拿不到 origin 字段,所以服務器不知道這個請求是從哪個域名過來的,而服務器這邊每個域名都對應著一個證書,服務器就不知道該返回哪個證書啦。
SNI 就是用來解決這個問題的,官方解釋是
然后有將近 25% 的瀏覽器不支持該字段的擴展,這個問題有兩個通用解決方案:
- 使用 VIP 服務器,每個域名對應一個 VIP,然后 VIP 與統一接入服務對接,通過 ip 來分發證書,不過運維成本很高,可能也需要大量的 VIP 服務器
- 采用多泛域名,將多個泛域名證書打包進一個證書,可以看看淘寶頁面的證書
它的缺點是每次添加域名都需要更新證書。
幾個細節知識點
1. 證書選擇
證書有多張加密方式,不同的加密方式對 CPU 計算的損耗不同,安全級別也不同。TLS 在進行第一次握手的時候,客戶端會向服務器端?say hello,這個時候會告訴服務器,它支持哪些算法,此時服務器可以將最適合的證書發給客戶端。
2. 證書的吊銷
CA 證書的吊銷存在兩種機制,一種是在線檢查,client 端向 CA 機構發送請求檢查 server 公鑰的靠譜性;第二種是 client 端儲存一份 CA 提供的證書吊銷列表,定期更新。前者要求查詢服務器具備良好性能,后者要求每次更新提供下次更新的時間,一般時差在幾天。安全性要求高的網站建議采用第一種方案。
大部分 CA 并不會提供吊銷機制(CRL/OCSP),靠譜的方案是為根證書提供中間證書,一旦中間證書的私鑰泄漏或者證書過期,可以直接吊銷中間證書并給用戶頒發新的證書。中間證書的簽證原理于上上條提到的原理一樣,中間證書還可以產生下一級中間證書,多級證書可以減少根證書的管理負擔。
很多 CA 的 OCSP Server 在國外,在線驗證時間比較長,如果可以聯系 CA 供應商將 Server 轉移到國內,效率可以提升 10 倍左右。
3. PKI 體系
比較主流的兩種方案是 HPKP 和 Certificate Transparency:
- HPKP 就是用戶第一次訪問的時候記下 sign 信息,以后不匹配則拒絕訪問,這存在很大的隱患,比如 Server 更新了證書,或者用戶第一次訪問的時候就被人給黑了
- Certificate Transparency 意思就是讓 CA 供應商透明化 CA 服務日志,防止 CA 供應商偷偷簽證
小結
看了不少文章,對 CA 和證書相關的知識做了一些總結,可能不全面,也可能存在表述錯誤或者知識性錯誤,歡迎拍磚!
拓展閱讀
- http://jamielinux.com/docs/openssl-certificate-authority/index.html
- http://www.ert7.com/service/knowledge/3999.html
轉自:
https://www.barretlee.com/blog/2016/04/24/detail-about-ca-and-certs/
?
?
?
?
總結
- 上一篇: qca956x flash u
- 下一篇: OneNote | 插件/使用技巧