第 1 章 SSL、TLS和密码学

第 1 章 SSL、TLS和密码学

我们生活在一个互联网时代。在20世纪的最后十年,互联网已经十分普及,并且永久性地改变了我们的生活方式。今天,我们依靠手机和计算机进行通信、购买商品、支付账单、旅行、工作,等等。很多人的口袋里总是装着处于开机状态的设备;我们并不只是连接到互联网,其实就是互联网的一部分。目前手机的数量已经超过了人口的数量。智能手机的数量已经达到数十亿,并且仍保持着快速增长。与此同时,诸多计划正酝酿将各种设备连接到同一网络。显然,这一切才刚刚开始。

所有连接到互联网的设备都有一个共同点,它们依赖安全套接字层(secure socket layer,SSL)和传输层安全(transport layer security,TLS)协议保护传输的信息。

1.1 传输层安全

人们最初设计互联网时,很少考虑到安全。这样的结果是,核心通信协议本质上是不安全的,只能依靠所有参与方的诚信行为。互联网在早期由少数节点(大部分是大学)构成,那时这也许行得通;但现在所有人都可以连接到互联网,这种方式便土崩瓦解。

SSL和TLS都是加密协议,旨在基于不安全的基础设施提供安全通信。这意味着,如果正确部署这些协议,你就可以对互联网上的任意一个服务打开通信信道,并且可以确信你会与正确的服务器通信,安全地交换信息(你的数据不会被他人截取,而且在接收时会保持原样)。这些协议保护着通信链路即传输层,这也是TLS名称的由来。

安全不是TLS的唯一目标。TLS实际上有以下四个主要目标(按优先顺序排列)。

  • 加密安全

    这是主要问题:为任意愿意交换信息的双方启用安全通信。

  • 互操作性

    独立的编程人员应该能够使用通用的加密参数开发程序和库,使它们可以相互通信。

  • 可扩展性

    你很快就会看到,TLS是一种能高效开发和部署加密协议的框架。其重要目标是独立于实际使用的加密基元(例如密码和散列函数),从而不需要创建新的协议,就允许从一个基元迁移到另一个。

  • 效率

    最终的目标是在实现上述所有目标的基础上保持性能成本在可接受的范围内。这需要尽量减少昂贵的加密操作的执行次数,并提供一个会话缓存方案,以避免这些加密操作在随后的连接中被执行。

1.2 网络层

互联网的核心是建立在IP(internet protocol)和TCP(transmission control protocol)协议之上的,这些协议用于将数据分割成小数据包进行传输。这些数据包在全世界范围内历经数千里的传输,在此期间需要跨越许多国家的许多计算机系统(称为跃点,hop)。由于核心协议本身不提供任何安全保障,任何有权访问通信链路的人都可以获得所有数据,并且可以在不被察觉的情况下改变这些数据。

IP和TCP不是唯一易受攻击的协议,还有一系列其他路由协议用于协助发现网络上的其他计算机。DNS和BGP就是这样的两个协议。它们同样是不安全的,可以被他人通过各种方式劫持。如果出现这种情况,发往一台计算机的连接可能由攻击者响应。

如果部署了加密,攻击者也许有能力得到加密数据的访问权限,但是不能解密数据或者篡改数据。为了避免伪装攻击,SSL和TLS依赖另外一项被称为公钥基础设施(public key infrastructure,PKI)的重要技术,确保将流量发送到正确的接收端。

为了理解SSL和TLS的运作,我们需要从描述网络通信的理论模型入手,即开放系统互联(open systems interconnection,OSI)模型,参见表1-1。简单来说,所有功能都被映射到七个层上。最底层是最接近物理通信链路的层,后面的层依次建立在其他层之上,提供更高级别的抽象。最顶层就是应用层,携带着应用数据。

注意

现实中的协议并非总能与OSI模型完全对应。比如SPDY和HTTP/2因为要对连接进行管理,所以被归入会话层协议,但它们却在数据加密以后生效。第五层及更高层的划分经常是模糊的。

表1-1 OSI模型层

层号

OSI层

描述

协议示例

7

应用层

应用数据

HTTP、SMTP、IMAP

6

表示层

数据表示、转换和加密

SSL/TLS

5

会话层

多连接管理

4

传输层

包或流的可靠传输

TCP、UDP

3

网络层

网络节点间的路由与数据分发

IP、IPSec

2

数据链路层

可靠的本地数据连接(LAN)

以太网

1

物理层

直接物理数据连接(电缆)

CAT5

以这种方式安排通信可以清晰地划分概念:高层的协议不必担心在底层实现的功能。进一步说,不同层次的协议可以加入通信或者从通信中删除,一种底层协议可以服务于多种上层协议。

SSL和TLS是这一原则如何在实践中运用的一个重要示例。它用于TCP协议之上,上层协议(如HTTP)之下。当不需要加密时,可以将TLS从模型中去掉,这并不会对上层协议产生影响(它们将直接与TCP协同工作)。当需要加密时,就可以利用TLS加密HTTP,以及其他TCP协议(比如SMTP、IMAP等)。

1.3 协议历史

SSL协议由Netscape公司开发,历史可以追溯到Netscape Navigator浏览器统治互联网的时代1。协议的第一个版本从未发布过,第二版则于1994年11月发布。第一次部署是在Netscape Navigator 1.1浏览器上,发行于1995年3月。

1若想了解更详细的SSL协议早期历史,建议阅读Eric Rescorla的SSL and TLS: Designing and Building Secure Systems(Addison-Wesley出版社于2001年出版),第47~51页。

SSL 2的开发基本上没有与Netscape以外的安全专家进行过商讨,所以有严重的弱点,被认为是失败的协议,最终退出了历史的舞台。这次失败使Netscape专注于SSL 3,并于1995年年底发布。虽然名称与早先的协议版本相同,但SSL 3是完全重新设计的协议。该设计一直沿用到今天。

1996年5月,TLS工作组2成立,开始将SSL从Netscape迁移至IETF。由于Microsoft和Netscape当时正在为Web的统治权争得不可开交,整个迁移过程进行得非常缓慢、艰难。最终,TLS 1.0于1999年1月问世,见RFC 2246。尽管与SSL 3相比,版本修改并不大,但是为了取悦Microsoft,协议还是进行了更名3

2TLS工作组,https://datatracker.ietf.org/wg/tls/documents/(IETF,检索于2014年6月23日)。

3Security Standards and Name Changes in the Browser Wars,http://tim.dierks.org/2014/05/security-standards-and-name-changes-in.html(Tim Dierks,2014年5月23日)。

直到2006年4月,下一个版本TLS 1.1才问世,仅仅修复了一些关键的安全问题。然而,协议的重要更改是作为TLS扩展于2003年6月发布的,并被集成到了协议中,这比大家的预期早了好几年。

2008年8月,TLS 1.2发布。该版本添加了对已验证加密的支持,并且基本上删除了协议说明中所有硬编码的安全基元,使协议完全弹性化。

协议的下一个版本正在开发过程中。该版本预计会成为一个主要版本,其目标是简化设计,除去安全性较弱或者不太需要的功能,并且提升性能。各位读者可以关注TLS工作组邮件列表的讨论4

4TLS working group mailing list archives,http://www.ietf.org/mail-archive/web/tls/current/(IETF,检索于2014年7月19日)。

1.4 密码学

密码学是一门通信安全的科学,同时也是一门艺术。虽然我们总是将密码学与现代联系在一起,但在上千年以前,人们事实上就已经开始利用它的力量了。考古发现,加密工具密码棒5首次被提及是在公元前7世纪。我们今天所知的密码学诞生于20世纪,用于军事领域;而它现在已经成为了我们日常生活的一部分。

5Scytale,https://en.wikipedia.org/wiki/Scytale(维基百科,检索于2014年6月5日)。

部署正确的密码能解决安全的三个核心需求:保持秘密(机密性)、验证身份(真实性),以及保证传输安全(完整性)。

本章剩余部分将对一个加密环境的基本构造进行讨论,展示安全性从何而来。同样,还会讨论加密体系通常是如何受到攻击的。密码学是一个非常多样化的领域,并且有非常深厚的数学基础。我会将视角保持在很宽泛的层面上,给大家介绍一些基础知识,使大家能够看懂后面的讨论。如果主题需要,我会在本书的其他部分更详细地介绍密码学的相关内容。

注意

如果想花更多时间学习密码学,你可以找到很多文献。我最喜欢的一本书是《深入浅出密码学》(Understanding Cryptography,作者是Christof Paar和Jan Pelzl,2010年由Springer出版)。

1.4.1 构建基块

在最底层,使用密码加密依赖于各种加密基元(cryptographic primitive)。每种基元都着眼于某个特定功能而设计。比如,我们会使用某个基元加密,使用另外一个基元进行完整性检查。单个基元本身的作用并不大,但是我们可以将它们组合成方案(scheme)和协议(protocol),从而提供可靠的安全性。

Alice和Bob是谁?

讨论密码学时,我们为了方便起见,通常会使用Alice和Bob这两个名字6。他们可以使枯燥的密码学命题变得更加有趣一些。大家公认,Ron Rivest在1977年介绍RSA密码系统的论文中,首次使用了这两个名字7。此后,又有其他一些名字进入了密码学文化。在这一章中,我将一位具备窃听能力的攻击者命名为Eve,并将另一位能够妨碍网络流量的主动攻击者命名为Mallory。

6Alice and Bob,https://en.wikipedia.org/wiki/Alice_and_Bob(维基百科,检索于2014年6月5日)。

7Security's inseparable couple,http://www.networkworld.com/article/2318241/lan-wan/security-s-inseparable-couple.html(Network World,2005)。

1. 对称加密

对称加密(symmetric encryption)**(private-key cryptography),是一种混淆算法,能够让数据在非安全信道上进行安全通信。为了保证通信安全,Alice和Bob首先得到双方都认可的加密算法和密钥。当Alice需要向Bob发送数据时,她使用这个密钥加密数据。Bob使用相同的密钥解密。Eve能够访问信道,所以可以看到加密数据;但因为没有密钥,所以看不到原始数据。Alice和Bob只要能保证密钥安全,就能一直安全地通信,如图1-1所示。

{%}

图 1-1 对称加密

注意

讨论加密时通常会使用到三个术语:明文(plaintext,即原始数据)、密钥(cipher,用于加密)和密文(ciphertext,即加密后的数据)。

对称加密可以追溯到上千年以前。比如,加密时将字母表中的每个字母替换成其他字母,解密时反向操作,这就是代替密码加密。在这个例子中,不存在密钥;安全性取决于保守加密方法的秘密。那就是最早的算法的例子。随着时间的流逝,我们采用了另一种方法。它是依照19世纪的一位密码破解专家Auguste Kerckhoffs的观察结果发展而来的8

8la cryptographie militaire,http://petitcolas.net/kerckhoffs/(Fabien Petitcolas,检索于2014年6月1日)。

即使攻击者知晓了整个密码系统除密钥以外的所有情报,系统仍然应当能保证安全。

Kerckhoffs的原则初看起来有些奇怪,但如果继续深刻思考,就会觉得有道理,原因如下。

  • 如果一种加密算法要得到广泛使用,就必须让其他人知道。当越来越多的人接触到这个算法,那么敌人得到这个算法的可能性也会增加。

  • 没有密钥的简单算法非常不便于在大群体中使用;每个人都可以解密所有人的通信。

  • 设计出优秀的加密算法非常困难。一种算法想要更安全,就得经过更多的曝光和审视。当需要采用一种新算法时,密码学家推荐使用保守的方法来确定算法是否安全,那就是算法需要经过许多年的破解尝试。

优秀的加密算法需要产出表面上看来随机的密文,这样攻击者就无法分析得出任何关于明文的信息。比如,替换密码就不是一种好算法,因为攻击者可以确定密文中各个字母的使用频率,并将其与英语中的字母使用频率进行对比。因为某些字母比其他字母使用得更频繁,攻击者可以利用这个结果恢复明文。如果加密算法优秀,攻击者只有一种方法,那就是尝试所有可能的解码密钥,俗称穷举密钥搜索(exhaustive key search)。

基于这一点,我们可以说密文的安全性完全取决于密钥。如果密钥是从某个非常大的密钥空间中选取出来的,那么破解也需要遍历所有这些可能的密钥,其数量极大,几乎不可能。我们可以说这种算法在计算上是安全性的。

注意

通常我们通过密钥长度来衡量加密强度;有一个假设是,密钥本质上是随机的,所以密钥空间才可以由密钥的位数来定义。比如,某个128位的密钥(被认为非常安全)有34×1037种可能的组合。

密码可以分为两大类:序列密码和分组密码。

  • 序列密码

    从概念上讲,序列密码(stream cipher)的操作过程与我们想象中加密的过程一致。将1字节的明文输入加密算法,就得到1字节的密文输出。在对端则进行相反的过程。整个过程持续重复,直到所有数据处理完成。

    序列密码的核心是生成一串称为密钥序列(keystream)的无穷序列,看似杂乱无章。加密就是将密钥序列中的1字节与明文序列中的1字节进行异或操作。因为异或操作是可逆的,所以解密就是将密文序列中的1字节与密钥序列中的相同字节进行异或操作。这个过程在图1-2中描述。

    {%}

    图 1-2 RC4加密

    只要攻击者无法预测密钥序列中对应位置的字节,就可以认为加密过程是安全的。基于这个理由,序列密码绝不能第二次使用相同的密钥,这一点非常关键。这是因为在实际使用中,攻击者知道或者可以预测特定区域的明文(请思考加密HTTP请求的情景;许多请求的请求方法、协议版本、请求头名称都是一样的)。当你知道明文,又观察到密文时,就可以解析一部分密钥序列。如果使用了相同的密钥,那么就可以解密后续的部分密文。为了解决这个问题,序列密码都与从长期密钥中提取出来的一次性密钥一同使用。

    RC4是最为人熟知的序列密码9。因为它很快很简单,所以一度非常流行。但是它已经不再安全。我将在7.5节中讨论它的弱点。其他现代的安全序列密码则由ECRYPT Stream Cipher Project10进行推进。

  • 分组密码

    分组密码(block cipher)每次加密一整块数据,并且现代的分组密码倾向于使用128位(16字节)大小的块。一种分组密码就是一个变换函数:接受输入并生成看似杂乱无章的输出。只要使用相同的密钥,每一个可能的输入组合都有唯一的输出。分组密码的关键特性是在输入上制造一个小变化(比如,在任意一处变换1位),从而得到大量输出变体。

    分组密码本身不是非常有用,因为它们自身有一些限制。第一个问题是,只能使用它们加密长度等于加密块大小的数据。因此在实际使用分组算法时,需要一个方法处理任意长度的数据。另一个问题是,分组密码是确定的。对于相同的输入,输出也是相同的。这个特性会使许多攻击成为可能,需要解决。

    实践中,人们通过称为分组密码模式(block cipher mode)的加密方案来使用分组密码。这种方案能规避这些限制,有时还可以添加身份验证。分组密码也可以作为其他加密基元的基础来使用,诸如散列函数、消息验证代码、伪随机数生成器,甚至序列密码。

    世界上最流行的分组密码是高级加密标准(advanced encryption standard,AES)11,可以使用128位、192位和256位的加密强度。

  • 填充

    分组密码的挑战之一是处理数据长度小于加密块大小的数据加密。举个例子,128位的AES需要16字节的输入数据并且产出相同长度的输出。如果你的数据刚好能归入16字节的块中,那正好。但如果不足16字节,怎么办?一种方法是追加额外的数据到明文的尾部。这些额外的数据就被称为填充(padding)。

    填充不能由任何随机数据构成,它必须遵循某种格式,这样接收方才可以发现填充并了解需要丢弃多少字节。在TLS中,加密块的最后1字节包含填充长度,指示填充有多少字节(不包含填充长度字节)。填充的每字节都被设置成与填充长度字节相同的值,如图1-3所示。这种方式使得接收方能够检查填充是否正确。

    为了在解密后丢弃填充,接收方检查数据块的最后1字节,删除它。接着,接收方删除指定长度的字节数,同时检查它们是否都是相同的值。

    {%}

    图 1-3 TLS填充示例

9RC4,https://en.wikipedia.org/wiki/RC4(维基百科,检索于2014年6月1日)。

10eSTREAM: the ECRYPT Stream Cipher Project,http://www.ecrypt.eu.org/stream/(European Network of Excellence in Cryptology II,检索于2014年6月1日)。

11Advanced Encryption Standard,https://en.wikipedia.org/wiki/Advanced_Encryption_Standard(维基百科,检索于2014年6月1日)。

2. 散列函数

散列函数(hash function)是将任意长度的输入转化为定长输出的算法。散列函数的结果经常被简称为散列(hash)。编程中普遍使用散列函数,但并非所有散列函数都适用于密码学。密码学散列函数有以下几个额外特性。

  • 抗原像性(单向性)

    给定一个散列,计算上无法找到或者构造出生成它的消息。

  • 抗第二原像性(弱抗碰撞性)

    给定一条消息和它的散列,计算上无法找到一条不同的消息具有相同的散列。

  • 强抗碰撞性

    计算上无法找到两条散列相同的消息。

散列函数最常用的使用场合是以紧凑的方式表示并比较大量数据。比如,为了避免直接比较两个文件(可能很难,比方说,它们存放于世界上不同的位置),你可以比较它们的散列。散列函数经常被称为指纹、消息摘要,或者简单称为摘要。

现在使用最为广泛的散列函数是SHA1,它的输出是160位。因为SHA1已经变弱,所以建议升级为SHA256的变种。与密码不同,散列函数的强度并不与散列长度对等。因为生日悖论(概率论中的常见问题)12,散列函数的强度最多只是散列长度的一半。

12Birthday problem,https://en.wikipedia.org/wiki/Birthday_problem(维基百科,检索于2014年6月1日)。

3. 消息验证代码

散列函数可以用于验证数据完整性,但仅在数据的散列与数据本身分开传输的条件下如此。否则攻击者可以同时修改数据和散列,从而轻易地避开检测。消息验证代码(message authentication code,MAC)或者使用密钥的散列(keyed-hash)是以身份验证扩展了散列函数的密码学函数。只有拥有散列密钥,才能生成合法的MAC。

MAC通常与加密一起使用。如果没有MAC,即使Mallory无法解码密文,她也能修改传输中的数据;加密提供了机密性但无法确保完整性。如果Mallory聪明到可以修改密文,她就可以诱使Bob接受并相信伪造的消息。当MAC和密文一起发送时,(和Alice共享散列密钥的)Bob就能确认消息并未遭到篡改。

任何散列函数都能用作MAC的基础,另一个基础是基于散列的消息验证代码(hash-based message authentication code,HMAC)13。HMAC本质就是将散列密钥和消息以一种安全的方式交织在一起。

13RFC 2104: HMAC: Keyed-Hashing for Message Authentication,http://tools.ietf.org/html/rfc2104(Krawczyk等,1997年2月)。

4. 分组密码模式

分组密码模式是为了加密任意长度的数据而设计的密码学方案,是对分组密码的扩展。所有分组密码模式都支持机密性,不过有些将其与身份验证联系起来。一些模式会将分组密码转换成序列密码。

它有许多输出模式,通常以首字母缩写来引用:ECB、CBC、CFB、OFB、CTR、GCM,诸如此类(不用担心这些缩写都代表什么)。我在这里只会介绍ECB和CBC:ECB是设计一种分组加密模式的反面例子,而CBC则仍是SSL和TLS的主要模式。GCM是TLS中相对较新的模式,从1.2版本开始才能使用。它提供了机密性和完整性,是当前可用的最好模式。

  • 电码本模式

    电码本(electronic codebook,ECB)模式是最简单的分组密码模式。它只支持数据长度正好是块大小的整数倍的情况,如果数据长度不满足这个条件,就得事先实施填充。加密就是将数据按块大小切分,再分别加密每一块。

    ECB的简单就是它的劣势。因为分组密码是确定的(输入相同,输出也相同),所以ECB也是如此。这就造成了严重的负面结果:(1) 密文中出现的模式显示出明文中对应出现的模式;(2) 攻击者可以发现信息是否重复;(3) 攻击者可以观察密文并且提交任意明文加密(在HTTP中通常是可能的,在一些其他情况下也可以),如此尝试足够的次数,就能猜出明文。这就是针对TLS的BEAST攻击的大致思路,7.2节会继续讨论。

  • 加密块链接模式

    加密块链接(cipher block chaining,CBC)模式是从ECB发展而来的下一步。为了解决ECB天生的确定性,CBC引入了初始向量(initialization vector,IV)的概念。即使输入相同,IV也可以使每次的输出都不相同,如图1-4所示。

    整个过程开始于生成一个随机IV(因此不可预测),长度与加密块相等。加密前,明文第一块内容与IV进行异或操作。这一步对明文进行了掩饰,并保证密文总是不尽相同。对于下一个加密块,使用上一块的密文作为IV,以此类推。这样一来,每次加密操作都是同一个加密链条中的一部分,这也是这种模式名称的由来。至关重要的是,IV必须通过线路传送到接收端,这个信息是成功解密所必需的。

5. 非对称加密

对称加密在高速处理大量数据方面做得非常好,然而随着使用它的团体增加,产生了更多的需求,使得对称加密无法满足。

  • 相同团体的成员必须共享相同的密钥。越多人加入,团体密钥出现问题的次数就越多。

  • 为了更好的安全性,你可以在每两个人之间使用不同的密钥,但是这个方法不可扩展。虽然3个人只需要3个密钥,但10个人就需要45(9+8+…+1)个密钥,而1000个人需要499 500个密钥!

  • 对称加密不能用于访问安全数据的无人系统。因为使用相同的密钥可以反转整个过程,这样的系统出现任何问题都会影响到存储在系统中的所有数据。

{%}

图 1-4 CBC模式加密

非对称加密(asymmetric encryption)又称为公钥加密(public key cryptography),它是另一种方法,使用两个密钥,而不是一个;其中一个密钥是私密的,另一个是公开的。顾名思义,一个密钥用于私人,另一个密钥将会被所有人共享。这两个密钥之间存在一些特殊的数学关系,使得密钥具备一些有用的特性。如果你利用某人的公钥加密数据,那么只有他们对应的私钥能够解密,如图1-5所示。从另一个方面讲,如果某人用私钥加密数据,任何人都可以利用对应的公钥解开消息。后面这种操作不提供机密性,但可以用作数字签名。

{%}

图 1-5 非对称加密

非对称加密使得大规模团体的安全通信大幅简化。假设你可以广泛并且安全地分享你的公钥(PKI的工作将会在第3章中进行讨论),那么任何人都可以向你发送消息,只有你可以阅读。如果他们使用各自的私钥签名,你还可以精确地知道消息出自何人之手。

虽然公钥密码的属性非常有趣,但它却非常缓慢,不适用于数据量大的场景。因此,它往往被部署于进行身份验证和共享秘密的协商,这些秘密后续将用于快速的对称加密。

RSA(得名于三个人的姓氏首字母:Ron Rivest、Adi Shamir和Leonard Adleman)是目前最普遍部署的非对称加密算法14。现在推荐的RSA强度是2048位,强度等同于112位的对称密钥。我将会在本章稍后更加详细地讨论密码强度。

14RSA,https://en.wikipedia.org/wiki/RSA_%28cryptosystem%29(维基百科,检索于2014年6月2日)。

6. 数字签名

数字签名(digital signature)是一个密码学方案。它使得验证一条电子消息或者一篇电子文档的真实性成为可能。前面描述的MAC就是一种电子签名,它可以利用事先安全交换的散列密钥验证真实性。虽然这种校验非常有用,但仍有不足,因为它仍然依赖于一个私有密钥。

借助公钥密码,数字签名可以与现实生活中的手写签名类似。我们可以利用公钥密码的非对称性设计出一种算法,使用私钥对消息进行签名,并使用对应的公钥验证它。

实际的方式依照选择的公钥密码体系而有所不同。下面以RSA为例。RSA可以用于加密,也可以用于解密。如果使用RSA私钥加密,那么仅能通过对应的公钥解密。我们可以利用这个性质,并且结合散列函数,实现数字签名。

(1) 计算希望签名的文档的散列。不论输入文档的长度如何,输出长度总是固定的。比如,使用SHA256就是256位。

(2) 对结果散列和一些额外的元数据进行编码。比如,接收方需要知道你使用的散列算法,否则不能处理签名。

(3) 使用私钥加密编码过的数据,其结果就是签名,可以追加到文档中作为身份验证的依据。

为了验证签名,接收方接收文档并使用相同的散列算法独立计算文档散列。接着,她使用公钥对消息进行解密,将散列解码出来,再确认使用的散列算法是否正确,解密出的散列是否与本地计算的相同。这个方案的强度取决于加密、散列以及编码组件各自的强度。

注意

并非所有的数字签名算法都与RSA的工作方式一致。事实上,RSA是一个特例,因为它可以同时用于加密和数字签名。其他流行的公钥密码算法则不能用于加密,比如DSA和ECDSA,它们依赖其他方式进行签名。

7. 随机数生成

在密码学中,所有的安全性都依赖于生成随机数的质量。在本章中,你已经看到,安全性构建于已知的算法和未知的密钥之上;而密钥最简单的形式就是非常长的随机数。

之所以说随机数不易生成,是因为计算机是十分善于预测的,它们会严格按照指令执行。如果告诉它生成一个随机数,它很可能做不好这项工作15。真正的随机数只能通过观测特定的物理处理器才能得到。没有的话,计算机将关注于收集少量的(entropy)。这通常意味着监视按键状态、鼠标移动,以及各种外设(比如硬盘)的交互情况。

15一些新型处理器内建了适于加密使用的随机数产生器。也有一些专业外设(比如,以闪存盘的形式)可以为操作系统提供额外的熵。

通过这种方式收集熵是一种真随机数生成器(true random number generator,TRNG),但是直接使用这种方式并不足够可靠。打个比方,你可能需要生成一个4096位的密钥,但是系统可能只有数百位的熵可用。如果没有可靠的外部事件可以收集到足够的熵,系统就可能会停止。

基于上面的原因,我们在实际使用中依靠的是伪随机数生成器(pseudorandom number generator,PRNG)。当然,PRNG也要利用少量真正的随机数使系统运转起来。这个过程被称为种子设定(seeding)。利用种子,PRNG根据需要构造出无限数量的伪随机数。普通用途的PRNG被常常用于编程,但它们并不适用于密码学,尽管其输出看起来就是随机的。加密安全伪随机数生成器(cryptographically secure pseudorandom number generator,CPRNG)是不可预测的PRNG。这个性质对安全来说非常关键,一定不能让攻击者对观察到的CPRNG输出进行内部状态的逆向工程。

1.4.2 协议

加密基元本身其实没什么用,诸如加密和散列算法。我们只有将这些元素组合成方案和协议,才能满足复杂的安全需求。为了说明我们需要怎么做,先来看一个简化的密码协议,这个协议可以使Alice和Bob安全地通信。我们的目标是全部三个重要需求:机密性、完整性和真实性。

我们假设协议允许交换任意数量的消息。因为对称加密擅长对大量数据进行加密,所以选取我们最喜欢的AES算法来进行数据加密。使用AES,Alice和Bob可以安全地交换消息,Mallory看不到他们通信的内容。但是这还不够,因为Mallory还可以干其他事情,比如,神不知鬼不觉地修改消息。为了解决这个问题,我们使用只有Alice和Bob知道的散列密钥计算每个消息的MAC。在发送消息的同时,也发送消息的MAC。

现在,Mallory再也不能修改消息了。然而,她仍然可以丢弃或者重发任意消息。为了解决这个问题,我们扩展协议,为每条消息指定序号。最为重要的是,我们将序号作为MAC计算数据的一部分。如果发现序号出现空缺,就能知道消息丢了。如果我们发现序号出现重复,就检测重放攻击。为了得到最佳结果,我们应使用某个特殊消息来标记会话结束。如果没有这个消息,Mallory能够悄悄地结束(截断)会话。

如果所有措施都已到位,Mallory最多只能做到阻止Alice和Bob与其他人进行通信。我们对此无能为力。

到目前为止,一切都好,但是我们仍然有一大块缺失:Alice和Bob如何协商得到需要的两个密钥(一个用于加密,一个用于完整性验证),同时还要当心Mallory?我们通过为协议增加两个额外的步骤来解决这个问题。

首先,在会话的开始,我们使用公钥密码对会话双方进行身份验证。举个例子,Alice生成一个随机数,并要求Bob对其签名以证明真的是他。Bob也要求Alice做相同的事情。

除了身份验证之外,我们还可以使用密钥交换方案对加密密钥进行秘密协商。继续举例,Alice可以生成所有密钥,用Bob的公钥加密,再发送给Bob,这就是RSA密钥交换的工作方式。我们也可以使用Diffie-Hellman(DH)密钥交换协议作为替代。后者相对速度更慢,但提供了更多的安全特性。

最后,我们的协议完工时的状态是:(1) 以握手阶段开始,包括身份验证和密钥交换;(2) 接下来是数据交换阶段,保证机密性和完整性;(3) 以关闭序列结束。站在宏观的角度来看,我们的协议与SSL和TLS完成的工作相似。

1.4.3 攻击密码

复杂系统往往会受到多种方式的攻击,密码系统也不例外。首先,你可以攻击加密基元本身。如果密钥很短,攻击者可以暴力破解。这种攻击通常需要相当多的运算能力和时间。对攻击者来说,如果系统使用的基元存在已知缺陷,他就可以使用解析攻击,从而更简单、更快地达成攻击目标。

人们一般都能很好地理解加密基元,因为它们相对直接,并且只完成一件工作。整体方案往往更容易遭受攻击,因为它们引入了额外的复杂性。在某些场景下,即使是密码学家也会争论执行特定操作的正确方法;但不论是基元还是方案,都比协议更安全。因为协议引入了更多的复杂性,并且攻击界面也大得多。

此外,也存在针对协议实现(implementation)的攻击;换言之,就是利用软件的bug。比如,绝大多数密码库都使用C甚至汇编这样的低级语言编写(出于性能的原因),非常容易引入灾难性的编程错误。即便没有这些bug,要实现基元、方案和协议,保证它们不被滥用,也需要很高的技巧。举个例子,某些算法的本地实现可以被计时攻击(timing attack)所利用,攻击者可以通过观察特定操作执行的时间破解加密。

有一种现象也非常普遍,那就是没有密码经验的程序员企图实现(甚至设计)加密协议和方案,理所应当地造成了不安全的结果。

所以,我们通常会说加密被绕过,而不是被攻击。这句话意味着使用的基元都很坚实,但软件体系不牢固。再进一步说,密钥是非常诱人的攻击目标:如果我们可以更轻松地闯进服务器拿到密钥,为什么还要花费数月时间暴力破解它?许多失败的加密案例都可以参照下面的简单规则避免:(1) 使用完善的协议,不要自己设计;(2) 使用高级库,避免直接操作加密;(3) 使用完备的基元,辅以足够强壮的密钥长度。

1.4.4 衡量强度

我们使用攻破某个基元所需执行的操作数量衡量密码系统的强度,以安全位数来表示。最容易做到的符合正确部署的行为就是部署长度足够强的密码,而且规则很简单:大部分系统部署128位(2128次操作)就足够了;如果需要长期的安全或者较大的安全宽限期,则使用256位。

注意

对称密码系统的强度按位数增加以几何基数增长,这意味着密码增加1位,强度翻一倍。

实际使用的情况更复杂一些,因为并非所有操作的安全性都能同等度量。所以,对于对称加密的操作、非对称加密的操作、椭圆曲线加密算法以及其他操作,我们使用不同的位数。你可以使用表1-2中的信息将一种大小转换为另一种大小。

表1-2 改编自ECRYPT2(2012)的安全级别和对应的安全强度位数

编号

保护

对称

非对称

DH

椭圆曲线

散列

1

个人实时攻击

32

2

对抗小规模组织非常短期的保护

64

816

816

128

128

3

对抗中等规模组织的短期保护

72

1008

1008

144

144

4

对抗专业代理机构非常短期的保护

80

1248

1248

160

160

5

短期保护(10年)

96

1776

1776

192

192

6

中期保护(20年)

112

2432

2432

224

224

7

长期保护(30年)

128

3248

3248

256

256

8

长期保护,增加对量子计算机的防御能力

256

15 424

15 424

512

512

这份数据是我从2012年的一份关于密钥和算法强度的报告16中节选出来的。它不仅粗略地展示了不同类型算法的位数对应关系,而且根据攻击者的能力和保护的时间长度两个方面定义了强度。尽管我们对安全与否的讨论都倾向于假设在现在这个时间点,但实际上安全性是一个与时间相关的函数。加密的强度会随时间发生变化,这是因为随着时间的推移,计算机会更快、更便宜。安全性同时也是与资源相关的函数。一个短密钥对个人来说可能不可破解,但专业代理机构就可以达成破解目标。因此,当我们讨论安全性时,提出诸如“针对谁的安全”和“多长时间的安全”这种问题会更有价值。

16ECRYPT2 Yearly Report on Algorithms and Keysizes,http://www.ecrypt.eu.org/(European Network of Excellence for Cryptology II,2012年9月30日)。

注意

因为无法做到精确衡量密码强度,所以你可以找到各种不同的推荐。它们大多数非常相似,只有一点点区别。以我的经验,ENISA(European Union Agency for Network and Information Security,欧洲网络与信息安全联合机构)提供了高级文档,可以以多种层次17给大家清晰的指导18。如果需要查阅和比较其他推荐文档,请访问keylength.com19

17Recommended cryptographic measures - Securing personal data,https://www.enisa.europa.eu/activities/identity-and-trust/library/deliverables/recommended-cryptographic-measures-securing-personal-data(ENISA,2013年11月4日)。

18Algorithms, Key Sizes and Parameters Report,https://www.enisa.europa.eu/activities/identity-and-trust/library/delive-rables/algorithms-key-size-and-parameters-report-2014(ENISA,2013年10月29日)。

19BlueKrypt: Cryptographic Key Length Recommendation,http://www.keylength.com/(BlueKrypt,检索于2014年6月4日)。

尽管表1-2提供了非常有用的信息,但你可能会发现它们难以使用,因为那些值与我们通常使用的密钥长度不对应。在实践中,你会发现表1-3在将一组安全位转换成另一组时更有用20

20NIST Special Publication 800-57: Recommendation for Key Management - Part 1: General, Revision 3,http://csrc.nist.gov/publications/nistpubs/800-57/sp800-57_part1_rev3_general.pdf(NIST,2012年7月)。

表1-3 常用密钥长度的加密强度映射

对称

RSA/DSA/DH

椭圆曲线

散列

80

1024

160

160

112

2048

224

224

128

3072

256

256

256

15 360

512

512

1.4.5 中间人攻击

针对传输层安全性的攻击绝大多数来自中间人(man-in-the-middle,MITM)攻击。这意味着除了会话双方的两个团体,还存在一个恶意团体。如果攻击者只是监听双方的会话,我们称之为被动网络攻击(passive network attack)。如果攻击者主动改变数据流或者影响双方会话,我们则称之为主动网络攻击(active network attack)。参见图1-6。

{%}

图 1-6 SSL/TLS威胁的概念模型

1. 取得访问权

在很多案例中,攻击者需要接近受害人或服务器,或者取得通信设施的访问权。无论是谁,只要能进入线路和中间通信节点(比如路由器),就能够看到线路上通行的数据帧,并且能够对它们进行干预。可以通过割开电缆21、与运营商共谋22或者直接侵入设备23来获取访问权。

21The Creepy, Long-Standing Practice of Undersea Cable Tapping,http://www.theatlantic.com/international/archive/2013/07/the-creepy-long-standing-practice-of-undersea-cable-tapping/277855/(《大西洋月刊》,2013年7月16日)。

22New Details About NSA's Collaborative Relationships With America's Biggest Telecom Companies From Snowden Docs,http://www.matthewaid.com/post/59765378513/new-details-about-nsas-collaborative(《华盛顿邮报》,2013年8月30日)。

23Photos of an NSA “upgrade” factory show Cisco router getting implant,http://arstechnica.com/tech-policy/2014/05/photos-of-an-nsa-upgrade-factory-show-cisco-router-getting-implant/(Ars Technica,2014年5月14日)。

理论上,执行MITM攻击的最简单方法是加入网络,然后将受害者的通信重新路由到恶意节点。现在很多人都在使用的无线网络并没有身份验证机制,任何人都可以加入,所以尤其容易受到这种攻击。

其他攻击方式包括妨碍域名解析、IP地址路由等的路由基础设施。

  • ARP欺骗

    地址解析协议(address resolution protocol,ARP)用于在局域网中将MAC地址24与IP地址进行关联。进入网络的攻击者可以声明任何IP地址,并对网络流量进行有效的重路由。

  • WPAD劫持

    浏览器使用Web代理自动发现协议(web proxy auto-discovery protocol,WPAD)自动获取HTTP代理的配置。WPAD使用了好几种方法,包括DHCP和DNS。为了攻击WPAD,攻击者在局域网中启动一台服务器并将其通知到那些寻找服务的本地客户端。

  • DNS劫持

    只要攻击者能通过注册或者改变DNS配置来劫持某个域名,就可以劫持访问这个域名的所有流量。

  • DNS缓存中毒

    DNS缓存中毒(DNS cache poisoning)是一种攻击者利用DNS缓存服务器的缺陷在缓存中注入非法域名信息的攻击方式。成功完成这种攻击以后,受影响的DNS服务器的所有用户都将收到攻击者构造的非法信息。

  • BGP路由劫持

    边界网关协议(border gateway protocol,BGP)是一种互联网骨干网络用于发现如何精确定位IP地址段的路由协议。如果某个非法路由信息被一个或更多路由器所接受,所有通往某个特定IP地址段的流量都将被重定向到另一处,即攻击者那里。

24这种情况下,MAC代表媒体接入控制。它是生产厂家指定给网卡的唯一标识。

2. 被动攻击

被动攻击对于未加密的流量最为有用。整个2013年,世界各国的政府机构对互联网流量的常规监控和大量存储变得人尽皆知。例如,有人宣称英国谍报部门GCHQ记录了英国所有的互联网流量并保存三天时间25。你的电子邮件消息、照片、互联网聊天记录,以及其他数据都存放在某处的一个数据库中,等待着进行相互参照,分析其是否具有特殊目的。如果大量数据都像这样处理,那么可以想象某些数据会存储更长时间甚至无限期存放。为了应对这些,IETF宣布“渗透监听就是攻击”26,需要尽可能使用加密进行防御。

25GCHQ taps fibre-optic cables for secret access to world's communications,http://www.theguardian.com/uk/2013/jun/21/gchq-cables-secret-world-communications-nsa(《卫报》,2013年6月21日)。

26RFC 7258: Pervasive Monitoring Is an Attack,http://tools.ietf.org/html/rfc7258(S. Farrell和H. Tschofenig,2014年5月)。

即使针对加密数据,被动攻击仍可以作为全局策略的一个要素发挥作用。比如,可以先保存抓取的加密数据,直到破解加密之后再使用。当前困难的事情在十年以后可能就会变得简单,因为随着时间的推移,计算机会越来越强大,越来越便宜,也有可能发现加密基元的弱点。

让事情变得更为糟糕的是,计算机系统通常存在一个严重的配置缺陷,使得攻击者可以追溯解密记录的数据。TLS中最常见的密钥交换算法是基于RSA算法的;在使用这种算法的系统中,密钥交换使用的RSA密钥也用于解密过去所有的会话。其他密钥交换算法不存在这个问题,被称为支持前向保密(forward secrecy)。不幸的是,大部分系统使用的仍然是RSA算法。举个例子,爱德华·斯诺登使用的加密邮件系统Lavabit就不支持前向保密。FBI拿着法庭的传票,迫使Lavabit交出了他们的加密密钥27。有了密钥,FBI就能解开有记录的通信(当然,只要他们记录过),于是爱德华·斯诺登的邮件就被破译了。

27Lavabit,https://en.wikipedia.org/wiki/Lavabit(维基百科,检索于2014年6月4日)。

被动攻击的效果非常好,这既是因为还有非常多的数据未被加密,也是因为大量收集信息的过程可以全自动化。截至2014年7月,到达Gmail的邮件只有58%进行过加密28,这可以很好地说明现在的状况。

28Transparency Report: Email encryption in transit,http://www.google.com/transparencyreport/saferemail/(Google Gmail,检索于2014提7月27日)。

3. 主动攻击

当大家谈论MITM攻击时,指的基本上都是主动攻击。Mallory可以利用主动攻击以某种方式干预通信。传统的MITM会攻击目标的身份验证系统,诱使Alice认为她正在与Bob通信。如果攻击成功,Mallory会收到Alice的消息并转给Bob。虽然Alice发送消息时会进行加密,但这并不是问题。因为她的发送对象是Mallory,后者可以用她与Alice协商的密钥解密消息。

在TLS方面,对Mallory来说,理想的场景是Alice认为她给出的证书是有效的并且接受证书。那样的话,攻击天衣无缝,基本上无法被发现29。要使证书有效,需要攻击者扮演公钥证书体系的角色。近年来,已经有很多这类攻击的案例了,我在第4章中记录了那些众所周知的案例。利用验证代码中的bug,攻击者可以构造看似有效的证书。历史上,这个领域内的bug较为常见,我会在第6章中讨论其中一些示例。如果前面所有的攻击最终都失败了,Mallory就会发送一个无效证书碰碰运气,看Alice会不会强行无视证书警告。几年前这种情况在叙利亚发生过30

29除非你非常执着地亲自跟踪所有遇见过的证书,某些浏览器扩展可以做到(比如Certificate Patrol for Firefox)。

30A Syrian Man-In-The-Middle Attack against Facebook,https://www.eff.org/deeplinks/2011/05/syrian-man-middle-against-facebook(The Electronic Frontier Foundation,2011年5月5日)。

作为强大的应用发布平台,浏览器的势头不断上升,也为主动攻击提供了新的攻击向量。在这个场景中,身份验证不会受到攻击,攻击者操纵受害者的浏览器,使浏览器提交精心构造的请求从而破坏加密。近年来,这些攻击向量已经被用作新的攻击手段,对TLS进行了攻击。大家可以在第7章中找到更多内容。

主动攻击的攻击力非常强大,但更难扩展。与被动攻击仅仅将观察的分组进行复制(这种操作非常简单)相比,主动攻击需要进行更多处理并投入更多努力来跟踪个体连接。所以主动攻击对软件和硬件的需求会多很多。重定向大流量也容易被发现。同样,大规模证书欺诈攻击也很难奏效,原因是应付这么多个人和组织对各种网站证书的跟踪监测非常困难。最有希望成功的攻击方式是利用执行中的漏洞,绕过身份验证。但是,像这样能带来毁灭性结果的程序错误较为罕见。

基于上述原因,主动攻击最可能用于攻击高价值的个人目标。主动攻击无法实现自动化,这意味着它们需要额外的工作,消耗很大,也因此更难以证明其价值。

有迹象表明NSA在一个名为QuantumInsert31的项目中部署了一套庞大的设施,可以用来攻击互联网上的几乎任意主机。

31Attacking Tor: How the NSA Targets Users' Online Anonymity,https://www.schneier.com/essays/archives/2013/10/attacking_tor_how_th.html(Bruce Schneier,2013年10月4日)。

这个项目是MITM方案的变种。它不是针对目标的加密系统,而是利用选定对象个人的浏览器漏洞投递攻击。NSA在通信设施中放置一些特殊的分组注入节点,从而得到比真实服务器更快的连接请求响应能力,并使它可以将部分流量重定向到漏洞利用的服务器。

目录

  • 版权声明
  • 前言
  • 第 1 章 SSL、TLS和密码学
  • 第 2 章 协议
  • 第 3 章 公钥基础设施
  • 第 4 章 攻击PKI
  • 第 5 章 HTTP和浏览器问题
  • 第 6 章 实现问题
  • 第 7 章 协议攻击
  • 第 8 章 部署
  • 第 9 章 性能优化
  • 第 10 章 HTTP严格传输安全、内容安全策略和钉扎
  • 第 11 章 OpenSSL
  • 第 12 章 使用OpenSSL进行测试
  • 第 13 章 配置Apache
  • 第 14 章 配置Java和Tomcat
  • 第 15 章 配置Microsoft Windows和IIS
  • 第 16 章 配置Nginx
  • 第 17 章 总结