赞
踩
为了让读者能更通俗易懂地了解一些密码技术中的常见概念及基本原理,本文不会涉及密码学相关算法和数学证明的知识。我们将主要讲下对称密码、非对称密码和混合密码系统,然后引出中间人攻击的问题。为了解决这个问题,我们还需要了解下消息摘要、数字签名和数字证书几个概念,最终再介绍 Charles 是如何拦截 HTTPS 消息的。
我们以明文传输为例来看下信息在传递过程中可能存在的几个问题。在上图的例子中,Alice 和 Eve 都喜欢 Bob,Alice 向 Bob 发了条明文消息表白,Eve 在中间拦截并篡改了这条消息。这个过程中涉及到了几个问题:
因此如果想保证信息被安全传输就需要满足对应的几个性质:
接下来分别介绍这几种密码技术。
为了防止信息被窃听,可以使用对称密码技术对消息进行加密和解密。由于对称密码在加密和解密时共享同一把密钥,因此也称为共享密钥密码(Shared Key Cryptography);又由于这把共享密钥需要双方私密地妥善保管,因此也称为私密密钥密码(Private Key Cryptography)。在对称密码通信过程中,Alice 使用共享密钥对信息进行加密,Bob 使用同一个共享密钥对信息进行解密。由于这个共享密钥只有 Alice 和 Bob 知道,即使 Eve 窃取到了消息,也是加密后的密文,没有密钥是解密不了的(本文不考虑密码破译),从而保证了消息的机密性。
常见的对称密码算法包括 DES、AES 等。其中由于现在 DES 的密文可以在短时间内被破译(1999年用了22小时15分钟就破译了),因此现在 DES 除了用来解密以前的 DES 密文之外,不应该再用来加密了。
使用对称密码进行加密通信的流程如下:
利用对称密码进行通信非常简单,在双方开始通信前先协商好后续会话的共享密钥,确保共享密钥不落入第三方手中。接着 Alice 就可以直接开始用共享密钥加密明文并发送给 Bob 了,Bob 接收到密文后用协商好的共享密钥解密得到明文。这个过程中即使密文被第三方截获,第三方没有密钥也无法解密出原文,从而保证了通信的机密性。
对称密码很好地保证了通信的机密性,而且其运算速度非常快。整个通信过程看起来挺完美的,但这都是基于一个条件,就是需要确保通信双方能安全地获取到这把会话共享密钥。那么在通信之前,Alice 和 Bob 如何才能都安全地获取到这把共享密钥呢?肯定不能直接通过网络来交换共享密钥了。因为如果能直接安全地通过网络来交换密钥,那就能安全地传输消息,也就不存在对消息加解密的需求了。这就是对称密码中的密码配送问题了,这里简单提一下几个解决方案。
也就是事先以安全可靠的方式共享密钥,比如可以近距离直接将密钥放在存储卡中并交给对方。 但这并不适用于远距离的情况,除非亲自配送密钥,否则始终都存在被中途截获的可能。另外,对于人数很多的情况也不适合,比如 1000 个人要互相进行通信则需要 (1000 * 999 / 2 = 499500)把密钥,管理起来也是个问题。
使用这种方式之前需要先配置一台充当密钥分配中心的计算机,每次要开始通信时,KDC 会生成一把会话密钥。每个人只需要和 KDC 事先共享密钥,然后 KDC 通过这个事先共享的密钥将会话密钥加密并传给他即可。
在 Diffie-Hellman 密钥交换中,通信双方 Alice 和 Bob 通过交换一些公开的信息各自生成相同的密钥,而这些交换的信息即使被 Eve 截获也无法计算出 Alice 和 Bob 所使用的密钥。简单地说,通信双方 A 和 B 各自生成一对 DH 密钥对(包含公私钥),再交换各自的公钥(即使中途被第三方窃取也没关系),然后双方就可以利用自己的私钥和对方的公钥计算出会话密钥了,而且能确保双方计算出来的会话密钥是相同的。
不使用对称密码进行加解密,转而使用非对称密码。
非对称密码由一把公钥和一把私钥组成密钥对。由于加密和解密使用的是不同的密钥,其中公钥是可以被公开的,任何人都可以获取,因此非对称密码也称为公开密钥密码(Public Key Cryptography)。在对称密码中,加密和解密使用了相同的密钥。而在非对称密码中,加密使用公钥加密,解密则使用私钥解密。这样我们就通过公开的方式将公钥发送给消息发送方,而私钥完全由消息接收方保管,确保不泄露私钥。因此,只要拥有公钥,则任何人都可以对消息加密,但只有拥有私钥的人才能对密文进行解密。
非对称密码中的密钥对有个性质:用公钥加密的密文,只能由同一密钥对中的私钥解密;反之亦然,用私钥加密的密文,也只能由同一密钥对中的公钥解密。而什么时候用公钥加密/私钥解密,什么时候用私钥加密/公钥解密,是需要根据应用场景来决定的。在加密通信中一般都是通过公钥加密/私钥解密来保证通信的机密性的,稍后我们还会提到另一种应用场景。
到目前为止使用最广泛的非对称密码算法就是 RSA 算法了(RSA 为它的三位开发者的姓氏首字母组成:Ron Rivest, Adi Shamir, Leonard Adleman),它通常被用于非对称密码或数字签名(数字签名待稍后介绍)。
使用非对称密码进行通信的流程如下:
相比前面的对称密码通信过程,这里 Bob 在通信之前事先生成了密钥对,Alice 从 Bob 那拿到其中的公钥,后续 Alice 就可以用这把公钥加密明文并把密文发送给 Bob,这样就只有 Bob 能解密出原文了(前提是 Bob 能妥善保管好私钥)。
其实在现实应用中,一般不会直接使用非对称密码对整个消息加密,因为它非常慢,它在运算速度上比对称密码要慢成百上千倍。但是它可以解决对称密码的密钥配送问题,而对称密码又能很好地保证通信的机密性。二者各有长短,能否互相取长补短呢?密码学家们想出了一招:用非对称密码加密对称密码以解决密钥配送问题,用对称密码加密通信消息以提高运算速度,这种充分结合两者优势的系统就称为混合密码系统。HTTPS 中用到的 SSL/TLS 协议就是使用的混合密码系统。
在混合密码系统中,在会话开始前 Alice 向 Bob 请求他事先生成的密钥对中的公钥,同时 Alice 生成一把随机的会话密钥并通过 Bob 的公钥加密,然后发送给 Bob。Bob 接收到密文后,用自己的私钥解密得到会话密钥。于是在后续的通信过程中双方就都能愉快地使用共享密钥对消息进行加解密了。由于会话密钥相比传输的消息一般都短得多,因此这里非对称密码运算耗不了多少时间,而且只在会话的开始阶段才需要。这样一来,对称密码的密钥配送问题和非对称密码的运算速度慢的问题也就都解决了。
混合密码系统通信时序如下图所示:
这个通信流程看起来也挺完美的,但其实还是有个前提的:Alice 接收到的公钥需要确认确实来自 Bob,而不是某个中间人。试想,如果公钥来自某个中间人,那么用这把公钥加密的消息就没法用 Bob 的私钥解密了,反而那个中间人能够用他的私钥解密密文了。这就是传说中的中间人攻击。
非对称密码虽然解决了对称密码的密钥配送问题,但还有个中间人攻击问题。
中间人攻击是密码学和计算机安全领域中的术语,并不仅仅存在于非对称密码系统中。可以这么理解:通信双方 A 和 B 中间可能存在一个中间人 M,M 分别与 A 和 B 建立了通信,M 在中途拦截并篡改通信数据,使得 A 和 B 误以为他们正在直接通过一个私密的连接与对方通信。可能很多人都想到了,抓包软件 Charles 就充分利用了中间人攻击的原理,我们后面还会再稍微详细地介绍下 Charles 是如何捕获 HTTPS 数据包的。
这里我们基于前面的非对称密码通信过程模拟的一次中间人攻击,但其实混合密码系统的通信过程也一样,实际上,只要是直接分发公钥的通信都存在中间人攻击的问题。
在这个例子中,Alice 的公钥请求被拦截并由 Eve 向 Bob 重新发起公钥请求,Eve 收到 Bob 返回的公钥 Pb 并保存后,Eve 返回了自己的公钥 Pe 给 Alice,这里 Alice 以为公钥就是真的来自 Bob。后续通信 Alice 就直接用 Eve 的公钥 Pe 加密消息了,这样 Eve 拦截到密文后就可以使用自己的私钥 Se 进行解密、篡改、重新用 Bob 的公钥 Pb 加密并发送给 Bob。最终 Bob 接收到密文后使用自己的私钥 Sb 解密得到了被篡改后的消息。
值得一提的是,这里的中间人攻击实际上并未破解非对称密码本身(即经过公钥加密的消息还是只能用同一密钥对中的私钥解密),但却达到了偷梁换柱的目的。所以我们要解决的问题其实可以归结为:Alice 如何确保接收到的公钥来自期望的通信对象 Bob 并且未被中间人篡改。解决方案就是数字证书,但在介绍它之前,我们需要先了解下消息摘要和数字签名两个概念。
消息摘要也称作做单向哈希函数(One-way Hash Function)或数字指纹(Digital Fingerprint),都是指代同一个概念。消息摘要可以用来保证消息的完整性,即防止消息被篡改。消息摘要有一个输入和一个输出,其中输入称为消息(Message),输出称为摘要(Digest)。
一个单向哈希函数具有以下几个特点:
常见的消息摘要算法包括 MD4、MD5、SHA-1、SHA-2(包括 SHA-256、SHA-384、SHA-512 等)、SHA-3 等。其中 MD4、MD5、SHA-1 不安全,即目前已经能够找到生成相同哈希值的两条不同消息了,除非用于兼容目的,一般不再使用了。
那么消息摘要是如何保证消息完整性的呢?消息发送方需要先计算出明文的消息摘要,然后将明文和消息摘要一同发送给接收方,接收方接收到消息后也根据明文计算出一个消息摘要。只有当发送前和接收后计算出的消息摘要相等才能确保消息在传输过程中未被篡改。反之,只要这个文件被改动过,即使只改动了 1bit,也会生成完全不同的消息摘要,导致校验失败,从而识别出篡改。
消息摘要除了应用到了后面的数字签名,另一个常见的例子是,从 Ubuntu 官网下载安装包的时候,就提供了 SHA-256(以前一般用 MD5) 的消息摘要,用于校验安装包的完整性。可以通过以下命令进行校验:
$ echo "add4614b6fe3bb8e7dddcaab0ea97c476fbd4ffe288f2a4912cb06f1a47dcfa0 *ubuntu-18.04.3-desktop-amd64.iso" | shasum -a 256 --check
该命令实际上是计算 ubuntu-18.04.3-desktop-amd64.iso 这个文件的 SHA-256 消息摘要,如果结果等于 add4614b6fe3bb8e7dddcaab0ea97c476fbd4ffe288f2a4912cb06f1a47dcfa0 就说明我们下载的文件未被篡改过。
讲完了消息摘要,可以开始介绍数字签名了。
在现实世界中,一个机构颁发证书的时候通常会加盖公章或签名,以此证明证书就是这个机构颁发的。而数字签名就是计算机领域中类似盖章签名的东西,可以把数字签名理解为现实世界中盖章签名的数字化版本,而且具有更高的安全性。数字签名主要利用了非对称密码和消息摘要两种技术。
我们来回顾下非对称密码的特点,一个密钥对中含有一把公钥和一把私钥,公钥可以公开发布给任何人,而私钥需要自己妥善保管。前面利用非对称密码进行加密通信时使用公钥加密/私钥解密。其实也可以反过来,根据不同的应用场景可以使用私钥加密/公钥解密,只是在进行加密通信时这么做并没有意义罢了。试想,如果发送者发送了用私钥加密的密文,一旦密文被截获,任何持有对应公钥的第三方就可以解密密文了(由于公钥是公开发布的,因此很容易获取),这样也就失去了对消息进行加密的意义了。但是如果使用私钥加密/公钥解密的话,接收到密文的公钥持有者就可以认为有且只有配套私钥的持有者才有能力加密这条消息了。这也就证明了这条信息必然是私钥持有者发出的,无法被伪装也无法抵赖。数字签名中用私钥加密也称为加签,用公钥解密也称为验签。我们前面提到的 SSH 免密登录其实也利用了这个性质,大概的原理就是:服务端先下发一个随机字符串给客户端,客户端通过私钥加签,服务器通过公钥验签来确定登录用户是否是可信任的。
由于非对称密码的运算速度非常慢,所以一般不会直接对整个消息加签,而是先对这个消息做哈希得到消息摘要,再对消息摘要进行加签。因此这里消息摘要不仅可以防篡改,还可以减少加签和验签的耗时。
下面是加签和验签的整个过程的流程图:
数字签名的加签验签流程和消息摘要的验证流程有着很大的相似度。不同点在于发送方会用私钥为消息摘要加签,传输的报文变成了“明文 + 数字签名”,而接收方需要利用公钥对数字签名进行验签,最后再将解密数字签名得到的消息摘要与直接从明文计算出的消息摘要做对比,从而完成数字签名的验签。
至此,我们终于可以开始介绍数字证书了。
之前我们说中间人攻击的问题归根结底就是无法确保公钥来自期望的通信对象,而数字证书的作用就是用来证明证书中的公钥就是来自证书持有人。证书中的内容包含持有人公钥、持有人信息、认证机构信息、证书有效期限以及认证机构加签的数字签名等。而最核心的东西就是持有人公钥和认证机构加签的数字签名。数字证书由认证机构签发。
认证机构 CA 可以分为根 CA (Root CA)和中间 CA(Intermediate CA),并由一个根 CA 和多个中间 CA 组合成树形结构的层级,每一级中间 CA 的证书都由上一级签发,而根 CA 的证书则是自己为自己签发的。一般知名 CA 的根证书都会被预置在操作系统和浏览器的证书信任列表中,使得我们可以直接信任并使用根证书中的公钥对下一级证书进行验证。而有些根证书则需要我们手动添加以表示信任,比如 Charles 根证书。出于安全的考虑,一般根 CA 只会自签发根证书,或者为中间 CA 签发数字证书,但不会直接为终端用户签发,而中间 CA 可为终端用户或下一级中间 CA 签发数字证书。CA 树形层级如图所示:
证书申请流程如下:假设 Bob 要为自己的公钥申请一份数字证书,首先 Bob 事先生成密钥对,然后用个人信息及密钥对中的公钥向 CA 发起证书签名申请(CSR),CA 根据认证运作规范(CPS)审核 Bob 提交的信息。审核通过后,CA 使用自己的私钥为这些信息施加数字签名形成数字证书,并颁发给 Bob。
那么如何验证一份数字证书是否有效呢?我们可以使用 CA 的公钥验证证书中的数字签名,如果数字签名验签成功就能说明证书是可信的,那么就能确认证书中的公钥来自证书中声明的持有者了。但我们又该如何确认这个 CA 的公钥是可信的呢?因此我们还需要用上一级 CA 的公钥进行验证,直到最终用到了根证书中的公钥。因此数字证书的验证实际上是基于由各级 CA 构成的信任链的。
这里我们要先理解一点:信任是可以传递的。举个例子,有位新来的同事我还不熟悉,他跟我说了个事,我无法判断真假。但我相信我的上级,而我的上级绝对信任这位同事,他之前跟我说过这位同事从来不撒谎,那么我就能间接地也相信这位同事说的话了。这就是信任的可传递性。
接着我们再以验证一份 SSL 证书举个例子。当浏览器通过 HTTPS 访问一个网站并拿到网站的 SSL 证书时,首先会在证书信任列表中查找是否存在 SSL 证书的签发机构(即某个中间 CA)的数字证书。如果找到了,说明这个中间 CA 是可信任的,于是用这个中间 CA 的公钥对 SSL 证书中的数字签名验签。如果没找到,则继续递归找到根证书,通过根证书中的公钥对中间 CA 证书的数字签名验签,直到最终回溯到 SSL 证书的上一级 CA。这时我们就知道这个上级 CA 的公钥是可信的,就可以用来验证 SSL 证书里数字签名了,从而完成证书的验签。
现在我们再来看下有了数字证书后的混合密码系统是怎样进行通信的。之前 Bob 直接把公钥发送给 Alice,Alice 是没法确认这把公钥是否真的来自 Bob。而现在 Bob 可以直接给 Alice 发送数字证书了,Alice 在验证这份证书有效后就可以证明证书中的公钥确实来自 Bob,后续也就可以使用这把公钥加密共享密钥了。到这里这个混合密码系统就真的挺完美了。
最后我们讲讲 Charles 是如何实现 HTTPS 消息拦截的,原理就是中间人攻击,通信时序大致如下:
我们日常开发使用 Charles 抓包的同学都知道,要抓手机上的包首先需要主动安装 Charles 根证书,否则就没法解析 HTTPS 的包了。那么为什么要安装 Charles 根证书呢?在通信开始的阶段,客户端向服务端请求数字证书,本来应该是服务端返回数字证书,客户端用操作系统或浏览器内置在证书信任列表中的根证书来验证服务端证书是否有效就可以了。但是现在 Charles 在中间拦截了这个请求并向客户端返回了 Charles 自己签发的证书,如果我们没有在手机上安装 Charles 根证书就没法验证这份 Charles 签发的证书了,进而导致 Charles 无法解析 HTTPS 的包了。
安装了 Charles 的根证书后,我们就可以使用根证书中的公钥成功验证 Charles 返回的数字证书 Cc 了。然后客户端生成随机会话密钥,用 Charles 返回的证书 Cc 中的公钥加密会话密钥发送给它以为的服务端,实际中途又被 Charles 拦截了,Charles 用自己的私钥解密得到会话密钥,然后用服务端证书 Cs 中的公钥重新加密发送给服务端。到这里,客户端、服务端以及 Charles 都拥有了后续要用的会话密钥了。后续客户端用会话密钥加密发出的密文被 Charles 拦截到后,Charles 可轻易地用会话密钥解密、篡改并重新加密,再发给服务端,导致服务端收到了被篡改后的数据。这就是 Charles 拦截 HTTPS 消息的原理了。
图解密码技术:图解密码技术(第3版) (豆瓣)
Crypto 101:AspEncrypt.com - Crypto 101
Sunny Classroom - YouTube
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。