You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

151 lines
12 KiB
Markdown

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# 25 | 固若金汤的根本(下):数字签名与证书
上一讲中我们学习了对称加密和非对称加密,以及两者结合起来的混合加密,实现了机密性。
但仅有机密性,离安全还差的很远。
黑客虽然拿不到会话密钥,无法破解密文,但可以通过窃听收集到足够多的密文,再尝试着修改、重组后发给网站。因为没有完整性保证,服务器只能“照单全收”,然后他就可以通过服务器的响应获取进一步的线索,最终就会破解出明文。
另外,黑客也可以伪造身份发布公钥。如果你拿到了假的公钥,混合加密就完全失效了。你以为自己是在和“某宝”通信,实际上网线的另一端却是黑客,银行卡号、密码等敏感信息就在“安全”的通信过程中被窃取了。
所以,在机密性的基础上还必须加上完整性、身份认证等特性,才能实现真正的安全。
## 摘要算法
实现完整性的手段主要是**摘要算法**Digest Algorithm也就是常说的散列函数、哈希函数Hash Function
你可以把摘要算法近似地理解成一种特殊的压缩算法,它能够把任意长度的数据“压缩”成固定长度、而且独一无二的“摘要”字符串,就好像是给这段数据生成了一个数字“指纹”。
换一个角度,也可以把摘要算法理解成特殊的“单向”加密算法,它只有算法,没有密钥,加密后的数据无法解密,不能从摘要逆推出原文。
![](https://static001.geekbang.org/resource/image/28/d8/2865d2c77466efb7a480833bcb27f9d8.png)
摘要算法实际上是把数据从一个“大空间”映射到了“小空间”所以就存在“冲突”collision也叫碰撞的可能性就如同现实中的指纹一样可能会有两份不同的原文对应相同的摘要。好的摘要算法必须能够“抵抗冲突”让这种可能性尽量地小。
因为摘要算法对输入具有“单向性”和“雪崩效应”输入的微小不同会导致输出的剧烈变化所以也被TLS用来生成伪随机数PRFpseudo random function
你一定在日常工作中听过、或者用过MD5Message-Digest 5、SHA-1Secure Hash Algorithm 1它们就是最常用的两个摘要算法能够生成16字节和20字节长度的数字摘要。但这两个算法的安全强度比较低不够安全在TLS里已经被禁止使用了。
目前TLS推荐使用的是SHA-1的后继者SHA-2。
SHA-2实际上是一系列摘要算法的统称总共有6种常用的有SHA224、SHA256、SHA384分别能够生成28字节、32字节、48字节的摘要。
你可以用实验环境的URI“/25-1”来测试一下TLS里的各种摘要算法包括MD5、SHA-1和SHA-2。
```
https://www.chrono.com/25-1?algo=md5
https://www.chrono.com/25-1?algo=sha1
https://www.chrono.com/25-1?algo=sha256
```
## 完整性
摘要算法保证了“数字摘要”和原文是完全等价的。所以,我们只要在原文后附上它的摘要,就能够保证数据的完整性。
比如你发了条消息“转账1000元”然后再加上一个SHA-2的摘要。网站收到后也计算一下消息的摘要把这两份“指纹”做个对比如果一致就说明消息是完整可信的没有被修改。
如果黑客在中间哪怕改动了一个标点符号,摘要也会完全不同,网站计算比对就会发现消息被窜改,是不可信的。
不过摘要算法不具有机密性,如果明文传输,那么黑客可以修改消息后把摘要也一起改了,网站还是鉴别不出完整性。
所以,真正的完整性必须要建立在机密性之上,在混合加密系统里用会话密钥加密消息和摘要,这样黑客无法得知明文,也就没有办法动手脚了。
这有个术语叫哈希消息认证码HMAC
![](https://static001.geekbang.org/resource/image/c2/96/c2e10e9afa1393281b5633b1648f2696.png)
## 数字签名
加密算法结合摘要算法我们的通信过程可以说是比较安全了。但这里还有漏洞就是通信的两个端点endpoint
就像一开始所说的,黑客可以伪装成网站来窃取信息。而反过来,他也可以伪装成你,向网站发送支付、转账等消息,网站没有办法确认你的身份,钱可能就这么被偷走了。
现实生活中,解决身份认证的手段是签名和印章,只要在纸上写下签名或者盖个章,就能够证明这份文件确实是由本人而不是其他人发出的。
你回想一下之前的课程在TLS里有什么东西和现实中的签名、印章很像只能由本人持有而其他任何人都不会有呢只要用这个东西就能够在数字世界里证明你的身份。
没错,这个东西就是非对称加密里的“**私钥**”,使用私钥再加上摘要算法,就能够实现“**数字签名**”,同时实现“身份认证”和“不可否认”。
数字签名的原理其实很简单,就是把公钥私钥的用法反过来,之前是公钥加密、私钥解密,现在是私钥加密、公钥解密。
但又因为非对称加密效率太低,所以私钥只加密原文的摘要,这样运算量就小的多,而且得到的数字签名也很小,方便保管和传输。
签名和公钥一样完全公开,任何人都可以获取。但这个签名只有用私钥对应的公钥才能解开,拿到摘要后,再比对原文验证完整性,就可以像签署文件一样证明消息确实是你发的。
![](https://static001.geekbang.org/resource/image/84/d2/84a79826588ca35bf6ddcade027597d2.png)
刚才的这两个行为也有专用术语,叫做“**签名**”和“**验签**”。
只要你和网站互相交换公钥,就可以用“签名”和“验签”来确认消息的真实性,因为私钥保密,黑客不能伪造签名,就能够保证通信双方的身份。
比如,你用自己的私钥签名一个消息“我是小明”。网站收到后用你的公钥验签,确认身份没问题,于是也用它的私钥签名消息“我是某宝”。你收到后再用它的公钥验一下,也没问题,这样你和网站就都知道对方不是假冒的,后面就可以用混合加密进行安全通信了。
实验环境的URI“/25-2”演示了TLS里的数字签名它使用的是RSA1024。
## 数字证书和CA
到现在,综合使用对称加密、非对称加密和摘要算法,我们已经实现了安全的四大特性,是不是已经完美了呢?
不是的,这里还有一个“**公钥的信任**”问题。因为谁都可以发布公钥,我们还缺少防止黑客伪造公钥的手段,也就是说,怎么来判断这个公钥就是你或者某宝的公钥呢?
真是“按下葫芦又起了瓢”,安全还真是个麻烦事啊,“一环套一环”的。
我们可以用类似密钥交换的方法来解决公钥认证问题,用别的私钥来给公钥签名,显然,这又会陷入“无穷递归”。
但这次实在是“没招”了,要终结这个“死循环”,就必须引入“外力”,找一个公认的可信第三方,让它作为“信任的起点,递归的终点”,构建起公钥的信任链。
这个“第三方”就是我们常说的**CA**Certificate Authority证书认证机构。它就像网络世界里的公安局、教育部、公证中心具有极高的可信度由它来给各个公钥签名用自身的信誉来保证公钥无法伪造是可信的。
CA对公钥的签名认证也是有格式的不是简单地把公钥绑定在持有者身份上就完事了还要包含序列号、用途、颁发者、有效时间等等把这些打成一个包再签名完整地证明公钥关联的各种信息形成“**数字证书**”Certificate
知名的CA全世界就那么几家比如DigiCert、VeriSign、Entrust、Lets Encrypt等它们签发的证书分DV、OV、EV三种区别在于可信程度。
DV是最低的只是域名级别的可信背后是谁不知道。EV是最高的经过了法律和审计的严格核查可以证明网站拥有者的身份在浏览器地址栏会显示出公司的名字例如Apple、GitHub的网站
不过CA怎么证明自己呢
这还是信任链的问题。小一点的CA可以让大CA签名认证但链条的最后也就是**Root CA**,就只能自己证明自己了,这个就叫“**自签名证书**”Self-Signed Certificate或者“**根证书**”Root Certificate。你必须相信否则整个证书信任链就走不下去了。
![](https://static001.geekbang.org/resource/image/8f/9c/8f0813e9555ba1a40bd2170734aced9c.png)
有了这个证书体系操作系统和浏览器都内置了各大CA的根证书上网的时候只要服务器发过来它的证书就可以验证证书里的签名顺着证书链Certificate Chain一层层地验证直到找到根证书就能够确定证书是可信的从而里面的公钥也是可信的。
我们的实验环境里使用的证书是“野路子”的自签名证书在Linux上用OpenSSL命令行签发肯定是不会被浏览器所信任的所以用Chrome访问时就会显示成红色标记为不安全。但你只要把它安装进系统的根证书存储区里让它作为信任链的根就不会再有危险警告。
![](https://static001.geekbang.org/resource/image/a5/8f/a55051ca7ae941ae04791cdddde6658f.png)
## 证书体系的弱点
证书体系PKIPublic Key Infrastructure虽然是目前整个网络世界的安全基础设施但绝对的安全是不存在的它也有弱点还是关键的“**信任**”二字。
如果CA失误或者被欺骗签发了错误的证书虽然证书是真的可它代表的网站却是假的。
还有一种更危险的情况CA被黑客攻陷或者CA有恶意因为它即根证书是信任的源头整个信任链里的所有证书也就都不可信了。
这两种事情并不是“耸人听闻”,都曾经实际出现过。所以,需要再给证书体系打上一些补丁。
针对第一种开发出了CRL证书吊销列表Certificate revocation list和OCSP在线证书状态协议Online Certificate Status Protocol及时废止有问题的证书。
对于第二种因为涉及的证书太多就只能操作系统或者浏览器从根上“下狠手”了撤销对CA的信任列入“黑名单”这样它颁发的所有证书就都会被认为是不安全的。
## 小结
今天我们学习了数字签名和证书、CA是不是有种“盗梦空间”一层套一层的感觉你可以在课后再去各大网站结合它们“小锁头”里的信息来加深理解。
今天的内容可以简单概括为四点:
1. 摘要算法用来实现完整性能够为数据生成独一无二的“指纹”常用的算法是SHA-2
2. 数字签名是私钥对摘要的加密,可以由公钥解密后验证,实现身份认证和不可否认;
3. 公钥的分发需要使用数字证书必须由CA的信任链来验证否则就是不可信的
4. 作为信任链的源头CA有时也会不可信解决办法有CRL、OCSP还有终止信任。
## 课下作业
1. 为什么公钥能够建立信任链,用对称加密算法里的对称密钥行不行呢?
2. 假设有一个三级的证书体系Root CA=>一级CA=>二级CA你能详细解释一下证书信任链的验证过程吗
欢迎你把自己的学习体会写在留言区,与我和其他同学一起讨论。如果你觉得有所收获,也欢迎把文章分享给你的朋友。
![](https://static001.geekbang.org/resource/image/37/57/37c59439c36e75f610fe84c22009cc57.png)