数字签名与证书

黑客虽然拿不到会话密钥,无法破解密文,但可以通过窃听收集到足够多的密文,在尝试着修改,重组后发送给网站。因为没有完整性保护,服务器只能 “照单全收”,然后他就可以通过服务器的响应获取进一步的线索,最终就会破解出明文。

另外,黑客也可以伪造身份发布公钥。如果你拿到了假的公钥,混合加密就完全失效了。你以为自己是在和 “某宝” 通信,实际上网线的另一端却是黑客,银行卡号、密码等敏感信息就在 “安全” 的通信过程中被窃取了。

所以,在机密性的基础上还必须加上完整性、身份认证等特征,才能真正的安全。

摘要算法

实现完整性的手段主要是摘要算法,也就是常说的散列函数、哈希函数。

你可以把摘要算法近似的理解成一种特殊的压缩算法,他能够把任意长度的数据 “压缩” 成固定长度、而且独一无二的 “摘要” 字符串,就好像是给这段数据生成了一个数字 “指纹”。

换一个角度,也可以把摘要算法理解成特殊的 “加密算法”,他只有算法,没有密钥,加密后的数据无法解密,不能从摘要逆推出原文。

摘要算法实际上是把数据从一个 “大空间” 映射到了小空间,所以就存在 “冲突(colisin,也叫冲突)” 的可能性,就如同现实中的指纹一样,可能会有两份不同的原文对应相同的摘要。好的摘要算法必须能够 “抵抗冲突”,让这种可能性尽量地小。

因为摘要算法对输入具有 “单向性” 和 “雪崩效应”,输入的微小不同会导致输出的剧烈变化,所以也被TLS用来生成伪随机数(PRF,pseud random function)。

你一定在日常工作中听过、或者用过MD5,SHA-1,他们就是最常用的两个摘要算法,能够生成16字节和20字节长度的数字摘要。但这两个算法的安全强度比较低,不够安全,在TLS里已经被禁止使用了。

目前TLS推荐使用的是SHA-1的后继者:SHA-2。

SHA-2实际上是一系列摘要算法的统称,总共有6中,常用的有SHA224、SHA256、SHA384,分别能够生成28字节、32字节、48字节的摘要。

完整性

摘要算法保证了 “数字摘要” 和原文是完全等价的。所以只要在原文后附上它的摘要,就能够保证数据的完整性。

比如,你发了条消息:“转账1000元”,然后再加上一个SHA-2的摘要,网站收到后也计算一下消息的摘要,把这两份 “指纹” 做个对比,如果一直,说明消息是完整可信的,没有被修改。

如果黑客在中间哪怕改动了一个标点符号,摘要也会完全不同,网站计算比对就会发现消息被篡改,是不可信的。

不过摘要算法不具有机密性,如果明文传输,那么黑客可以修改消息后把摘要也一起改了,网站还是鉴别不出完整性。

所以,真正的完整性必须要建立在机密性之上,在混合加密系统里用的会话密钥机密信息和摘要,这样黑客无法得知明文,也没有办法动手脚了。

这有个术语,叫哈希消息认证码(HMAC)。

数字签名

加密算法结合摘要算法,我们的通信过程可以说是比较安全了。但这里还有漏洞,就是通信的两个端点就像一开始所说的,黑客可以伪装成网站来窃取信息。而返过来,你也可以伪装成你,向网站发送支付、转账等信息,网站没有办法确认你的消息,前可能就这么被偷走了。

现实生活中,解决身份认证的手段是签名和印章,只要在纸上写上签名或者盖个章,就能够证明这份文件确实是由本人而不是其他人发出的。

在TLS里有个东西和现实中的签名、印章很像,只能由本人持有,而其他任何人都不会有呢?只要用这个东西,就能够在数字世界里证明你的身份。

这个东西就是非对称加密里的 “私钥”,使用私钥再加上摘要算法,就能实现 “数字签名“,同时实现 ”身份认证“ 和 ”不可否认“。

数字签名的原理其实很简单,就是把公钥私钥的用法反过来,之前是公钥加密,私钥解密,现在是私钥加密、公钥解密。

但又因为非对称加密效率太低,所以私钥只加密原文的摘要,这样运算量就小的多,而且得到的数字签名也很小,方便保管和传输。

签名和公钥一样完全公开,任何人都可以获取。但这个签名只有用私钥对应的公钥才能解开,拿到摘要后,再对比原文验证完整性,就可以像签署文件一样证明消息确实是你发的。

刚才的这两个行为也有专用术语,叫做 ”签名“ 和 ”验签“。

只要你和网站互相交换公钥,就可以用”签名“和”验签“ 来确认消息的真实性,因为私钥保密,黑客不能伪造签名,就能保证通信双发的身份。

比如,你用自己的私钥签名一个消息 ”我是小明“。网站收到后用你的公钥验签,确认身份没问题,于是也用它的私钥签名消息 ”我是某宝“。你收到后再用它的公钥验一下,也没问题,这样你和网站就知道对方不是假冒的,后面就可以混合加密进行安全通信了。

数字证书和CA

到现在,综合使用对称加密,非对称加密和摘要算法,我们已经实现了安全的四大特性,是不是已经完美了呢?

不是的,这里还有一个 ”公钥的信任“ 问题。因为谁都可以发布公钥,我们还缺少防止黑客伪造公钥手段,也就是说,怎么判断这个公钥是你或某宝的公钥呢?

我们可以用类似密钥交换的方式解决公钥认证问题,用别的私钥来给公钥签名,显然,这又会陷入 ”无穷递归“。

但这次实在是 ”没招了“,要终结这个 ”死循环“,就必须引入 ”外力“,找一个公认的可行的第三方,让它作为 ”新人的起点,递归的终点“,构建起公钥的信任链。

这个 ”第三方“ 就是我们常说的CA(Certificate Authority,证书认证机构)。他就像网络世界里的公安局、具有极高的可信度,由他来给各个公钥签名,用自身的信誉来保证公钥无法伪造,是可信的。

CA对公钥的签名认证也是有格式的,不是简单地把公钥绑定在持有者身份上就完事了,还要包含序列号,用途,颁发者,有效时间等等,把这些打成一个包再签名,完整地证明公钥关联地这种信息,形成 ”数字证书“。

知名地CA全世界就那么几家,比如DigiCert、Verisign、Entrust、Let‘ s Encrypt等,它们签发地证书分DV、OV、EV三种,区别在于可信程度。

DV是最低的,只是域名级别的可行,背后是谁不知道。EV是最高的,经过了法律和审计的严格核查,可以证明网站拥有者的身份(在浏览器地址栏会显示出公司的名字,例如Apple、GitHub的网站)。

不过,CA怎么证明自己呢?

这还是信任链的问题。小一点的CA可以让大CA签名认证,但链条的最后,也就是RootCA,就只能自己证明自己了,这个就叫 ”自签名证书“ 或者 ”根证书“。你必须相信,否则整个证书信任链就走不下去了。

有了这个证书体系,操作系统和浏览器都内置了各大 CA 的根证书,上网的时候只要服务器发过来它的证书,就可以验证证书里的签名,顺着证书链(Certificate Chain)一层层地验证,直到找到根证书,就能够确定证书是可信的,从而里面的公钥也是可信的。

我们的实验环境里使用的证书是“野路子”的自签名证书(在 Linux 上用 OpenSSL 命令行签发),肯定是不会被浏览器所信任的,所以用 Chrome 访问时就会显示成红色,标记为不安全。但你只要把它安装进系统的根证书存储区里,让它作为信任链的根,就不会再有危险警告。

证书体系的弱点

证书体系(PKI,Public Key Infrastructure)虽然是目前整个网络世界的安全基础设施,但绝对的安全是不存在的,它也有弱点,还是关键的“信任”二字。

如果 CA 失误或者被欺骗,签发了错误的证书,虽然证书是真的,可它代表的网站却是假的。

还有一种更危险的情况,CA 被黑客攻陷,或者 CA 有恶意,因为它(即根证书)是信任的源头,整个信任链里的所有证书也就都不可信了。

这两种事情并不是“耸人听闻”,都曾经实际出现过。所以,需要再给证书体系打上一些补丁。

针对第一种,开发出了 CRL(证书吊销列表,Certificate revocation list)和 OCSP(在线证书状态协议,Online Certificate Status Protocol),及时废止有问题的证书。

对于第二种,因为涉及的证书太多,就只能操作系统或者浏览器从根上“下狠手”了,撤销对 CA 的信任,列入“黑名单”,这样它颁发的所有证书就都会被认为是不安全的。

小结

  • 摘要算法用来实现完整性,能够为数据生成独一无二的“指纹”,常用的算法是 SHA-2;
  • 数字签名是私钥对摘要的加密,可以由公钥解密后验证,实现身份认证和不可否认;
  • 公钥的分发需要使用数字证书,必须由 CA 的信任链来验证,否则就是不可信的;
  • 作为信任链的源头 CA 有时也会不可信,解决办法有 CRL、OCSP,还有终止信任。