数字证书作用
我们知道HTTPS比HTTP安全,它的安全在于通信过程被加密。然而加密算法是用对称加密,也就是说,客户端和服务端采用一个相同的密钥。为了让双方得到这个密钥,前期就有一个很重要的工作:协商密钥。
现在我们简单模拟一下通信过程:
- 客户端:hi,我准备跟你(xx.com)建立HTTPS通信。
- 服务端:好的,我就是xx.com,这是我的证书,你验证一下。
- 客户端:验证通过了,你的确是xx.com,我把密钥发给你,下面的通信咱们就加密了。
- 服务端:s&&(*3u247(
- 客户端:(&DY&#%%&#
上述只是简化后的过程, 我们可以看到协商密钥中有一个很重要的步骤:服务端要证明自己是xx.com。如何证明?证书+链式验证!
数字证书内容
执行以下的命令可以看到一个网站的证书内容(以www.baidu.com
为例):
openssl s_client -connect www.baidu.com:443
可以看到,证书就是这么一堆内容:
-----BEGIN CERTIFICATE-----
MIIJPzCCCCegAwIBAgIMCNBs8Cq2uU5UNfueMA0GCSqGSIb3DQEBCwUAMGYxCzAJ
UaCmeTg1cbvOTh7TFaWzF4YAyVk7lbXo4qa5eP0ZJotGlP1KQ1ASiOzJXzkb+7lS
7CJELk6Jz6IizNG0wtpj4G2CWOKB5Qm8LlGvPZBXVlzbKAu2hObLJhq+XIp883Gw
.....省略....
fi66YCxIwyCKGQZpdKxP+FX4w6vhcTlkSO59orvUFChBu6qdyoUQzBKD4M0fZEh+
iQioeqDNbX39fBP/7tZMBaUh7SlklDQkWbdgnUbKe1gSX90C2A91g/Sp7Cyzl6f8
U8f0AMvvyVwdPMmFCkDK3g85Cg==
-----END CERTIFICATE-----
看起来是一堆base64的编码,我们继续用openssl命令把证书内容打印出来,它符合x.509规格:
//先把证书内容保存在www.baidu.com.crt文件内
openssl x509 -text -noout -in www.baidu.com.crt
解码后输出内容如下:
Certificate:
Data:
Version: 3 (0x2)
Serial Number:
08:d0:6c:f0:2a:b6:b9:4e:54:35:fb:9e
Signature Algorithm: sha256WithRSAEncryption
Issuer: C=BE, O=GlobalSign nv-sa, CN=GlobalSign Organization Validation CA - SHA256 - G2
Validity
Not Before: May 3 01:48:02 2018 GMT
Not After : May 26 05:31:02 2019 GMT
Subject: C=CN, ST=beijing, L=beijing, OU=service operation department, O=Beijing Baidu Netcom Science Technology Co., Ltd, CN=baidu.com
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
00:af:a4:c3:2a:19:81:8e:22:9c:e5:44:92:39:30:
8a:c6:8c:fb:ca:1f:ba:4d:b0:39:33:05:9f:2b:3e:
d9:20:c1:63:30:99:92:6e:a1:2c:7f:28:c8:1e:d5:
e7:93:3d:f1:fc:62:c6:b3:32:67:5c:8d:98:96:4e:
f7:54:6c:d6:eb:83:64:b3:bb:2f:02:8f:a9:d3:58:
9c:96:57:e3:1c:77:3a:f4:0d:19:d8:46:4a:53:72:
c8:e7:f0:f3:71:d2:88:fe:f7:73:91:28:ba:3d:78:
1b:1e:c5:76:63:c6:88:21:b7:17:6c:3e:58:03:40:
f2:86:95:80:e7:20:6b:9a:77:92:af:61:36:5e:8f:
ac:f3:c2:85:72:0d:32:89:e4:ba:a2:9b:2a:c5:d2:
8c:4a:94:ba:8b:16:c5:11:02:eb:d9:78:32:1a:66:
f6:b5:bb:25:38:3e:94:bb:11:8d:46:14:60:5e:1c:
74:91:c1:8b:27:38:4b:87:82:03:15:97:a6:c5:86:
7c:7d:27:1e:c1:89:2b:14:66:66:e9:6c:cd:75:06:
40:5a:4c:3f:42:39:1d:4b:b1:16:08:df:83:06:a4:
e8:0d:a1:01:2e:d4:24:86:20:a2:2c:b1:cb:c2:c2:
ba:f6:07:c5:7d:0b:df:e1:fe:fd:74:92:b7:7e:8f:
a5:b3
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Key Usage: critical
Digital Signature, Key Encipherment
Authority Information Access:
CA Issuers - URI:http://secure.globalsign.com/cacert/gsorganizationvalsha2g2r1.crt
OCSP - URI:http://ocsp2.globalsign.com/gsorganizationvalsha2g2
X509v3 Certificate Policies:
Policy: 1.3.6.1.4.1.4146.1.20
CPS: https://www.globalsign.com/repository/
Policy: 2.23.140.1.2.2
X509v3 Basic Constraints:
CA:FALSE
X509v3 Subject Alternative Name:
DNS:baidu.com, DNS:baifubao.com, DNS:www.baidu.cn, DNS:www.baidu.com.cn, DNS:mct.y.nuomi.com, DNS:baifae.com, DNS:apollo.auto, DNS:*.baidu.com, DNS:*.baifubao.com, DNS:*.baidustatic.com, DNS:*.bdstatic.com, DNS:*.bdimg.com, DNS:*.hao123.com, DNS:*.nuomi.com, DNS:*.chuanke.com, DNS:*.trustgo.com, DNS:*.bce.baidu.com, DNS:*.eyun.baidu.com, DNS:*.map.baidu.com, DNS:*.mbd.baidu.com, DNS:*.fanyi.baidu.com, DNS:*.baidubce.com, DNS:*.mipcdn.com, DNS:*.news.baidu.com, DNS:*.baidupcs.com, DNS:*.aipage.com, DNS:*.aipage.cn, DNS:*.bcehost.com, DNS:*.safe.baidu.com, DNS:*.im.baidu.com, DNS:*.ssl2.duapps.com, DNS:*.baifae.com, DNS:*.baiducontent.com, DNS:*.dlnel.com, DNS:*.dlnel.org, DNS:*.dueros.baidu.com, DNS:*.su.baidu.com, DNS:*.91.com, DNS:*.hao123.baidu.com, DNS:*.apollo.auto, DNS:*.xueshu.baidu.com, DNS:*.bj.baidubce.com, DNS:*.gz.baidubce.com, DNS:*.smartapps.cn, DNS:click.hm.baidu.com, DNS:log.hm.baidu.com, DNS:cm.pos.baidu.com, DNS:wn.pos.baidu.com, DNS:update.pan.baidu.com
X509v3 Extended Key Usage:
TLS Web Server Authentication, TLS Web Client Authentication
X509v3 Subject Key Identifier:
45:36:AC:EA:1D:89:68:E1:2B:39:11:AD:23:9C:D1:59:36:8B:B0:CC
X509v3 Authority Key Identifier:
keyid:96:DE:61:F1:BD:1C:16:29:53:1C:C0:CC:7D:3B:83:00:40:E6:1A:7C
CT Precertificate SCTs:
Signed Certificate Timestamp:
Version : v1(0)
Log ID : BB:D9:DF:BC:1F:8A:71:B5:93:94:23:97:AA:92:7B:47:
38:57:95:0A:AB:52:E8:1A:90:96:64:36:8E:1E:D1:85
Timestamp : May 3 01:48:04.994 2018 GMT
Extensions: none
Signature : ecdsa-with-SHA256
30:45:02:20:50:84:C6:43:95:81:58:E1:5B:6E:CD:C9:
7A:E0:F7:B8:03:E4:A7:AC:57:40:45:06:41:81:21:9F:
E1:EF:20:D7:02:21:00:C4:DC:AB:F3:D1:94:EE:DF:BA:
1E:89:8D:34:00:9C:4D:BE:36:91:A7:20:F2:ED:37:D9:
0B:D4:69:59:53:CF:07
Signed Certificate Timestamp:
Version : v1(0)
Log ID : 6F:53:76:AC:31:F0:31:19:D8:99:00:A4:51:15:FF:77:
15:1C:11:D9:02:C1:00:29:06:8D:B2:08:9A:37:D9:13
Timestamp : May 3 01:48:04.625 2018 GMT
Extensions: none
Signature : ecdsa-with-SHA256
30:45:02:21:00:A2:DE:A2:E2:29:CB:AB:64:33:1F:FC:
DE:6A:A7:0A:EC:D8:B8:1D:63:72:4C:84:B8:B4:1E:A8:
75:21:73:B1:C9:02:20:59:88:21:97:BC:4C:D6:6C:11:
8E:46:49:05:78:64:D9:A5:7B:32:54:83:51:53:08:85:
77:A7:F7:4B:C4:B0:EE
Signature Algorithm: sha256WithRSAEncryption
89:08:0e:6a:b7:52:34:35:46:fd:1e:45:23:ba:4f:ee:f5:14:
12:87:5d:f5:9c:6b:e1:23:aa:be:7b:3a:b7:3d:be:7a:34:76:
43:d4:cb:92:72:8e:eb:65:a4:51:a0:a6:79:38:35:71:bb:ce:
4e:1e:d3:15:a5:b3:17:86:00:c9:59:3b:95:b5:e8:e2:a6:b9:
78:fd:19:26:8b:46:94:fd:4a:43:50:12:88:ec:c9:5f:39:1b:
fb:b9:52:ec:22:44:2e:4e:89:cf:a2:22:cc:d1:b4:c2:da:63:
e0:6d:82:58:e2:81:e5:09:bc:2e:51:af:3d:90:57:56:5c:db:
28:0b:b6:84:e6:cb:26:1a:be:5c:8a:7c:f3:71:b0:7e:2e:ba:
60:2c:48:c3:20:8a:19:06:69:74:ac:4f:f8:55:f8:c3:ab:e1:
71:39:64:48:ee:7d:a2:bb:d4:14:28:41:bb:aa:9d:ca:85:10:
cc:12:83:e0:cd:1f:64:48:7e:89:08:a8:7a:a0:cd:6d:7d:fd:
7c:13:ff:ee:d6:4c:05:a5:21:ed:29:64:94:34:24:59:b7:60:
9d:46:ca:7b:58:12:5f:dd:02:d8:0f:75:83:f4:a9:ec:2c:b3:
97:a7:fc:53:c7:f4:00:cb:ef:c9:5c:1d:3c:c9:85:0a:40:ca:
de:0f:39:0a
数字证书,没有很复杂的内容,它包括以下几样东西:
- 公钥:Public-Key
- 签名:Signature
- 签名算法: Signature Algorithm: sha256WithRSAEncryption
- 证书颁布机构:Issuer
- 过期时间:Validity
- 其他...
1~5是较为重要,其他的,例如一些扩展属性SAN
,稍作了解即可。
数字证书如何验证
平时我们写代码的时候为了验证请求的合法性,一般会用md5
来算出一个sign
值,该sign
值伴随请求一同发送给服务端。服务端用相同的key,md5
算出sign
,比对是否一致。例如:
//客户端签名
sign = md5(content + key)
//服务端校验签名
md5_Sign ?= md5(content + key)
HTTPS的证书校验其实差不多,只不过算法比md5
稍微复杂一点。
具体签名算法在证书里都会明确标明,例如baidu的证书就是用 Signature Algorithm: sha256WithRSAEncryption
签名。需要注意的是,不同证书颁发的时候会有不同的签名算法,有些老证书仍采用sha128
。
sha256WithRSAEncryption
大体是这样的:
//签名
sign = RSA_Encrypt(sha256(content), privateKey)
//校验签名
sha256_Content = RSA_Decrypt(sign, publicKey)
sha256_Content ?= sha256(content)
在非对称加密体系中,私钥
用来签名,公钥
用来校验签名。
到了HTTPS场景,A给B颁发证书,意味着这证书是用A的私钥
签名,以后必须用A的公钥
来校验。
那A的公钥
哪来?答案就是从A的证书里获得。问题又来了,我得验证一下A的证书才能用它的公钥
,对吧?假设A的证书是X颁发的,那就用X的公钥
验证。
同样,我们要验证X的证书,又需要Y的公钥
...
如此循环下来就成了一条所谓的证书链。循环必须有出口,出口就是系统安装的根证书,安装在系统的根证书是永远信任的,也就是说,可以拿它的公钥来验证下一级的证书,下一级又验证下下一级,如下图:
证书链说白了就是一个"找别人证明自己"的过程:
- A:我是A,不信你可以问下B,B给我做担保;
- B:我是B,不信你找下X,它能证明我是B;
- X:我是X,不信你找下Y,它能证明我是X;
- Y:我是Y,不信你找下ROOT,它能证明我是Y;
- ROOT:哎呀,我们是认识的啊,那就好办了,Y是真的...
ROOT必须可靠可信任,如果ROOT是伪造的,那么ABXY它们的话都不可信。
所以以前有些网站(例如12306)让用户添加根证书是很不负责任的,大家警惕。
以下是一个完整的证书链验证,执行命令:
[root] openssl s_client -connect www.baidu.com:443
CONNECTED(00000003)
depth=2 C = BE, O = GlobalSign nv-sa, OU = Root CA, CN = GlobalSign Root CA
verify return:1
depth=1 C = BE, O = GlobalSign nv-sa, CN = GlobalSign Organization Validation CA - SHA256 - G2
verify return:1
depth=0 C = CN, ST = beijing, L = beijing, OU = service operation department, O = "Beijing Baidu Netcom Science Technology Co., Ltd", CN = baidu.com
verify return:1
可以看到证书链有3层(一般也就只有3层),分别是*.baidu.com
、GlobalSign Organization Validation CA
和GlobalSign Root CA
。
- 第0层,验证
*.baidu.com
,需要找GlobalSign Organization Validation CA
这个证书; - 第1层,验证
GlobalSign Organization Validation CA
,需要找GlobalSign Root CA
这个证书; - 第2层,验证
GlobalSign Root CA
,它是一个根证书,而且在客户端的信任列表里,所以通过验证,验证结果“verify return:1”;
服务器的证书文件
在nginx,简单地把下面三个配好就可以用HTTPS了:
ssl on;
ssl_certificate ssl/sslchain.crt; //数字证书
ssl_certificate_key ssl/ssl.key; //私钥文件
私钥文件是用来在协商密钥的时候解密密钥的,这里不重点讨论,这个文件不能泄露。
证书文件一般会包含3个证书, 就是上面的*.baidu.com
、GlobalSign Organization Validation CA
和GlobalSign Root CA
。如果把第2层GlobalSign Organization Validation CA
删掉,证书链就断了,整个证书验证会失败。
调试工具
大家在调试证书问题的时候,建议用opnessl命令结合curl,把信息打印出来,了解会深刻一点。