第一章:TLS密码学

密码学是一门庞大的学科,但幸运的是,你只需要了解一些选定的部分就可以正确管理TLS。你不需要掌握数学,只需要掌握加密系统组件以及数据如何在加密和未加密状态之间流动。我们将学习这些基础知识。密码学一般有三个目标:完整性、机密性和不可否认性。

不同的加密工具支持这些目标的不同方面。

第一章:TLS密码学哈希和加密哈希对称加密公钥加密消息身份验证代码数字签名密钥长度破解算法密码套件密码套件名称备用密码名包括密码套件密码列表和密码排序当HIGH不够用时信任模型和证书颁发机构私钥保护TLS恢复完全正向保密服务器名称指示

哈希和加密哈希

哈希(hash)或校验和(checksum)是一种从任何数据块计算固定长度字符串的计算。不同的哈希算法产生不同长度的哈希,但算法产生的任何哈希的长度都不会改变。SHA256哈希的长度始终为256位,即64个十六进制字符。哈希可以是加密的,也可以不是。不同之处在于,加密哈希在实际应用中是不可逆的,正如我们将在这里看到的。哈希是一种完整性验证工具。

当你预期会损坏而不是故意篡改时,非加密哈希是有用的。我可以通过计算文本正文中的单词数,并在前面加上零使其成为固定数量的数字,为这本书创建一个简单的完整性检查哈希。你可以计算你的副本中的单词数,并将其与我的计数进行比较,看看是否匹配。TCP使用类似的数学方法来验证数据包在传输过程中没有损坏。这些是有效的哈希,但大多数哈希算法要复杂得多。它们也很容易伪造。你可以替换这本书中的两个关键单词,校验和仍然会匹配。

使用加密哈希,文件中的任何更改都会更改从该文件生成的哈希。假设一个文本文件包含以下文本:The wedding is at 10AM 。此文本的SHA256哈希值为bdf34d7f51fbe672325a29b0afd7b871513591a0c6dc2c96cb529f6cb8776070。如果有人更改了消息,将零改为一,从而声称婚礼在上午11点举行。通过这一个字符的更改,文件的SHA256哈希变为6c717735c4d360d2ae5503f765a6a153c0317720ad17e286988e87b52f25bf0。人类很难注意到微小的细节,所以即使是熟悉原始信息的人也可能会浏览篡改后的版本并声明其正确。然而,对哈希的最肤浅的检查表明,它们差异很大。

给定无限可能的文件,最终其中两个文件将具有相同的哈希值。这被称为哈希碰撞。对计算这种冲突的抵抗力是哈希加密的原因。

考虑一下“这本书中有多少单词”的哈希值。找到一个具有相同哈希值的文档是轻而易举的。它甚至不会注意到我们婚礼信息中的篡改。该算法对蓄意攻击的抵抗力为零。同样,TCP校验和也可以伪造。这些哈希值显然是非加密的。

如果你使用的是现代、强大的加密哈希,在工业规模的高端服务器场上找到一个与目标文件存在哈希冲突的文件将需要几十年的时间。你也不会机械地计算这样的文件;相反,你会尝试随机文件,直到找到匹配项。考虑到无限的时间、无限的计算能力和无限的预算,发现哈希冲突是不可避免的。我可能知道一条消息的哈希值为bdf34d7f51fbe672325a29b0afd7b871513591a0c6dc2c96cb529f6cb8776070,但我没有实际的方法来创建具有相同哈希的文件。

当软件发现哈希冲突时,数据几乎肯定与原始消息没有相似之处。一个人可能不会注意到消息中婚礼时间的改变,但他们肯定会注意到一条只包含二进制胡言乱语的消息。计算一个具有匹配哈希值的文件,该哈希值与原始哈希值足够相似,可以使用,同时仍包含您的更改?在当前的技术条件下,这不会发生。

是什么让加密哈希成功?当发现一个有用的碰撞时,婚礼早已过去,每个人都从此过上了幸福的生活。

对称加密

“加密”(encryption)的常见定义是对消息进行加密(scrambling ),使其内容只能被预期的接收者理解。一个邪恶的走狗会加密一条信息,这样只有他的王子才能读取它。密码算法(cryptographic algorithm)是一种加密方法。

对称(Symmetric )算法使用相同的密钥来加密和解密文本。如果你有密钥并且知道算法,你就可以加密和解密消息。对称算法依赖于密钥的保密性。过去一万年中使用的大多数加密算法都是对称的。计算和密码学之外的人可能会将对称算法称为代码(code),但这在我们的职业中是一个被过度使用的词,所以请避免给它带来进一步的负担。(“编码 ——encoding”是完全不同的东西,正如第3章所讨论的那样。)“cipher”一词通常在计算之外用于表示对称算法,但在系统管理中,cipher通常是本章稍后讨论的cipher套件的简写。

即使算法已知,设计良好的对称算法也能保持消息的机密性。考虑每个孩子学习的第一个代码:A=1,B=2,以此类推。这个算法很差,因为如果你知道算法,你就可以解密消息。您可以通过添加一个密钥来稍微改进此算法,该密钥是一个要添加到每个值的数字。密钥为13,意味着A=14和B=15可能看起来更难破解,但经验丰富的密码学家可以毫不费力地解密消息。现代对称算法,如CHACHA和AES,即使每个人都知道它们是如何工作的,也能保持机密性。

计算机提高了对称算法的标准。现代算法复杂,密钥长而繁琐。一旦两个实体可以交换密钥,它们就可以快速轻松地通信。问题是从一个到另一个获取密钥。这就是公钥加密发挥作用的地方。

公钥加密

你可能看过一部老电影,里面一枚硬币被切成复杂的拼图图案。两个从未谋面的间谍、罪犯或其他隐秘的人每人得到一半的硬币。当他们见面时,每人拿出一半的硬币。如果两半完美地结合在一起,每个人都可以放心,对方就是他们应该与之交谈的人。分割的藏宝图、中世纪的计数棒、将印第安纳琼斯带到约柜(Ark of the Covenant)的双面硬币——我们的文化一遍又一遍地使用这一想法。

这有点像公钥(public key)加密,也称为非对称(asymmetric)加密。

公钥加密的标准是Rivest、Shamir和Adelman(RSA)算法,以其发明者的名字命名。椭圆曲线数字签名算法(Elliptic Curve Digital Signature Algorithm —— ECDSA)是一种工作原理不同的新方法,但使用它的系统管理员级实践几乎相同。

你会听到“公钥加密”这个短语与身份验证、数字签名、HMAC和哈希、密钥交换以及各种其他术语联系在一起。这些系统是用公钥加密构建的,但它们不是公钥加密。不要让草率的语言迷惑你。公钥加密加密(Public key encryption encrypts)。这就是它所能做的。它的加密和解密方式让我们能够构建所有这些很酷的东西。在尝试任何其他事情之前,先了解公钥加密的工作原理。

公钥加密就像使用拼图硬币的两个部分作为加密密钥。每一片硬币都可以加密一条只能由另一片硬币解密的消息。如果我有其中一片硬币,我可以加密一条只有另一片硬币的持有者才能读取的信息。我的硬币甚至无法解密它加密的信息;只有同一枚硬币的另一片可以解密它。(这是公钥加密和对称加密之间的主要区别。)这两片硬币是成对的;任何拥有其中一片的人都可以加密和解密消息。

抓住你的那片硬币。你以后会需要它的。

公钥加密就像切开的硬币,但数字如此之大,以至于使用它们实际上需要计算机。当这些数字相乘时,它们的行为会很奇怪。你可以轻松廉价地生成两个相关的密钥,称为密钥对,其行为与这两枚硬币完全相同。你可以用一个密钥加密一条消息,只有这对密钥中的另一个密钥可以解密它。这就是公钥加密的全部功能。

数字与我们的硬币在几个方面有所不同。如果你有一个拼图分割的加拿大加元的一半,你可以再切一枚硬币来装它。用公钥对的一半和一堆电脑尝试同样的事情将比我们太阳的剩余寿命更长。拥有这对钥匙中的一把并不能帮助攻击者找出另一把钥匙。

复制公钥的一半是微不足道的;你复制文件。

假设我创建了一个公钥对。我保留着这对钥匙中的一把。我把另一把钥匙交给了我的首席打手(goon)维齐尼,然后才把他派往世界各地。其他人都没有这两把钥匙。我和我的打手可以使用这些密钥交换只能用配对中的另一个密钥读取的消息。我用我的一半把我的信息加密到我的谷歌上。希望我记得我说过的话,因为一旦消息被加密,我的密钥就无法解密我的消息。幸运的是,“发动战争并为此陷害罪犯”足够简短,连我都能记住。只有这对密钥中的另一个密钥可以解密该消息。我发了我的信息。任何窥探这条信息的人只会看到难以理解的胡言乱语。

当我的信息到达我的暴徒手中时,他们会使用他们的密钥对其进行解密。然后,他们可以使用密钥对响应进行加密,比如“我们绑架公主怎么样?”并将加密后的信息发送回我。只有我的一半密钥可以解密这条信息。

到目前为止,一切顺利。(So far, so good.)

公钥加密变得疯狂的地方在于,我们可以提供一对密钥中的一个。致全世界。把它放在你的网站上。或者是一块广告牌。买一个末日激光,把它刻在月球的近侧,大到任何人都能读懂。我们将这对密钥称为公钥(public key)。

这对钥匙中的另一把你完全保密。它被锁定在你的能力范围内。它永远不会离开你的控制。我们称之为私钥(private key)。(对称加密中使用的密钥也可能被称为“私钥”。不要让这让你感到困惑。)

当我用私钥加密消息时,任何人都可以获取公钥并解密。这并不能完全使我的消息保密。但世界上任何人都可以使用该密钥加密只有我才能读取的消息。任何人都能与我秘密通信。 如果你发布了一个密钥,我可以用这个密钥与你进行保密通信。

如果我是世界上唯一一个拥有私钥的人,那么任何收到用我的私钥加密的消息的人都可以非常确定该消息来自我。我不能可靠地声称我没有发送该消息。我们使用它来实现密码学的不可否认性(non-repudiation)目标。

为了向我的打手发送一条秘密信息,我用打手的公钥对其进行加密。只有我的暴徒才能阅读。我的暴徒用我的公钥加密了他的消息。

公钥密码学依赖于我们每个人保持私钥的真正私密性。如果我的私钥被偷走了,世界上任何人都可以假装是我。我只能承认自己严重无能,才能否认一条信息。

这项技术是大多数互联网加密的基础,包括TLS。每当你看到“公钥加密”一词时,立即考虑谁拥有哪些密钥。如果你对一个使用公钥加密的陌生系统负责,你的首要和直接责任是验证私钥是否被完全锁定。

如果公钥加密具有这些漂亮的功能,为什么还要费心使用对称加密呢?

与对称算法相比,公钥密码学需要数千倍的计算能力来加密、解密和验证。它很慢,很贵,而且会增加每个人的电费。

TLS和大多数其他利用公钥加密的应用程序结合了这两种算法。我们使用缓慢而昂贵的公钥算法来验证每个人,就对称算法达成一致,并为该算法交换随机密钥。所有进一步的通信都使用更快、更便宜的对称算法进行。

使用公钥密码学很复杂。公钥密码学用户必须就一系列算法、分配信任的方法等达成一致。这些的集合是公钥基础设施(public key infrastructure —— PKI)。如果你浏览过互联网,那么你正在使用TLS PKI。Microsoft的Active Directory包含自己的PKI,仅在域内使用。企业可以建立自己的PKI。OpenPGP还有另一个PKI。我们将把大部分精力花在讨论用于全球有效TLS的PKI上。第10章讨论了为学习目的构建自己的CA(一个私有PKI)。

消息身份验证代码

哈希很好,只要你注意在不同的通道上分发哈希和消息。如果我能拦截你的消息并更改消息和附带的哈希值,那么哈希值就没用了。这就是我们需要消息认证码(Message Authentication Code —— MAC)的地方。MAC是用只有发送方和接收方知道的对称加密密钥加密的哈希。

哈希消息认证码(Hashed Message Authentication Code —— HMAC)是使用特定加密哈希创建MAC的特定方法。您将看到基于这些哈希方法构建的HMAC名称,如HMAC-MD5和HMAC-SHA256。HMAC提供完整性和身份验证。只有拥有对称密钥的人才能加密或解密哈希。

TLS中使用的MAC通常是HMAC。

数字签名

从密码学角度来看,数字签名确保消息来自声称已签名的实体,并且没有其他人篡改消息。数字签名的消息被认为是真实的。它具有完整性、身份验证和不可否认性。

软件通过生成消息的HMAC对消息进行数字签名,用私钥对哈希进行加密,并将加密文件附加到消息中。任何拥有公钥的人(即每个人)都可以解密HMAC,独立计算消息的哈希值,并将两者进行比较。如果传输的哈希值和计算的哈希值匹配,则私钥持有者不会更改消息。

数字签名是您必须保护私钥的另一个原因。如果有人拥有你的私钥,他们可以发送你无法拒绝的消息。失去对私钥的独家访问权限就像把你的信用卡交给邻居十几岁的孩子。你可以收拾残局,但这会伤害到很多人。

如果收件人计算的消息哈希与数字签名中的哈希不同,则数字签名无效。消息被修改了。不要相信它。

密钥长度

密钥的长度(length)是私钥中的比特数。密钥长度为2048意味着密钥包含2048个随机零和一。对称加密和公钥加密都使用密钥长度。

如果有人想强行解密你的消息,他们可以一个接一个地尝试所有可能的随机密钥。这种暴力攻击消耗了大量的计算能力,但很容易在多台机器之间分配。每增加一位长度,潜在密钥的数量就会翻倍。如果你想要一个比2048位密钥更难猜测的密钥,那么它不是4096位密钥。这是一个2049位的密钥。4096位密钥的密钥数量是2048位密钥的22048-1倍。这是一个大约3.2x10616倍大的密钥空间。

对称和哈希算法通常具有固定的密钥长度。一些对称算法允许您在多个密钥长度之间进行选择。AES128使用128位密钥,而AES256的密钥长度是其两倍。算法的强度通常与密钥长度成指数正比。

公钥加密算法允许软件或系统管理员选择密钥长度。大多数软件都提供默认设置,您可能可以覆盖它。我建议不要这样做,除非有可靠的消息来源特别指示这样做。可靠的消息来源不包括强调的论坛帖子,无论它们多么符合你的偏见。

如果较长的密钥更难解密,你不应该总是使用尽可能长的密钥吗?绝对不是。公钥密码学的计算需要大量的处理器时间,较长的密钥需要更多的计算能力。您的服务器不是为了用于计算密钥而存在;它的存在是为了提供网页、电子邮件或其他一些最低限度可行的产品,关键计算是其中必要但附带的一部分。如果你的服务器把所有的时间都花在计算密钥上,那么它就没有什么可以执行其功能了。长密钥可以防止特定类型的攻击,同时干扰实际工作。

如果较长的密钥长度是不明智的,你会使用较短的密钥吗?不是在现实世界中。

密钥长度并非决定消息破解难度的唯一因素。算法也会影响它。使用2048位RSA密钥加密的消息与使用224位ECDSA密钥加密的信息一样难以破解,原因涉及许多可怕的数学运算。更长的密钥长度必然意味着“更难破解”。算法很重要。

如果您所在组织的标准不同,请遵循这些标准。金融机构等经常使用较长的密钥,因为它们是高价值目标。他们也有钱花在这些计算的硬件上。

如果你在使用旧软件时遇到困难,你可能需要增加默认密钥长度以符合当前标准。虽然1024位RSA密钥非常适合商业互联网的前二十年,但几年前很明显,暴力破解这些密钥很快就会变得可行。专家建议使用2048位密钥创建所有新密钥。软件默认值落后于建议,有时是因为旧硬件的性能原因,所以我不得不覆盖默认值,直到所有人都赶上。

是的,总有一天我们需要4096位RSA密钥。除非在数学或计算硬件方面取得重大突破,否则这将远远超出任何阅读本书的人的职业生涯。如果你展望未来,网站https://www.keylength.com/从多个标准中提取密钥长度建议。

最终,一切都会过时。

破解算法

“破坏”算法是什么意思?对于公钥加密,这意味着您可以根据公钥和加密文件计算私钥。对于哈希,这意味着您可以使用任何给定的哈希计算创建一个文件。破解算法有两种方式。有人可能会发现算法中的一个缺陷,该缺陷允许人们快捷地解密文件或计算碰撞(collision)。或者,当一个单一实体(如政府或公司)能够积累足够的处理能力,通过暴力破解算法时,该算法就被认为是失败的。更快的计算机使两者都更容易。

虽然密码学是一门古老的手艺,有着悠久而光荣的传统,但基于计算机的密码学只有几十年的历史。在互联网商业化之前,处理器时间非常昂贵,每个部门都要为其CPU使用量付费。Unix仍然包含跟踪用户消耗多少计算的功能,因此财务部门可以要求付款。计算机使许多算法在纸和笔上都不可行。

测试和破解这些算法需要不成比例的大量计算时间。想想打字机大小的恩尼格玛密码机,以及布莱切利·帕克庞大但复杂得多的恩尼格玛密码破解硬件。一个人可以加密的东西需要整个团队强制解密。这种动态在商业互联网的早期一直存在。

早期的计算机加密算法,其中许多包含在SSL和TLS中,都是仓促的,测试不足,并提供了许多机会来学习基于计算的密码学是如何工作的。这些算法中的许多都是在接触现实后破解的。我们抛弃了它们,从错误中吸取了教训。

例如,MD5和SHA-1是SSL早期版本的标准哈希。计算MD5哈希碰撞需要装满计算机的建筑,而且还需要几个世纪的时间。SHA-1哈希需要更多的计算能力来计算,因此即使它们更难破解,它们的使用频率也较低。

计算一直在发展。我们学到了更多关于密码学的知识。破解算法成为了赢得声望的一种方式。几年后,计算MD5碰撞成为现实。MD5被宣布为过时,并鼓励每个人停止使用它。SHA-1与其说是故意缓解MD5的过时,不如说是最后一种算法。它在十年或二十年的相同滥用中表现良好,但今天你可以在云提供商那里花几千美元计算SHA-1哈希冲突。它还不是微不足道的,但肯定不是不可能的昂贵。

较新的算法,如ECDSA和SHA-2家族,建立在经验的基础上。这些算法有望在读这本书的人的职业生涯之外继续存在。我们需要更多不同的算法,所以当有人变得聪明并打破这些算法时,我们就有了替代品。

当密码学家创建新的算法时,他们和他们的同事会攻击它们。他们还很好地估计了暴力破解所需的计算能力。尽管硬件不断进步,但只有预计在几个世纪内保持不可逆的加密哈希算法才能被广泛接受。密码学界必须广泛同意新算法是合适的,并将其部署在向用户推出的应用程序中。开发和部署需要数年时间。

损坏的算法不再保证机密性或完整性。希望到那时,你的所有软件都已更新,可以提供其他算法。设计您的应用程序,以便可以轻松添加和删除算法。

许多互联网协议都遵循Jon Postel的健壮性原则:“做什么要保守,接受别人的什么要自由。”(be conservative in what you do, be liberal in what you accept from others)你的应用程序可以传输最好的数据,并弥补别人的不足。我们都在互联网上。每个人都能交流的事实是一个奇迹,我们都知道当你急于创造奇迹时会发生什么。

此规则不仅不适用于TLS,还会危及您的服务器和客户端。每个TLS版本都指定了可接受的算法。较旧版本的TLS使用脆弱或完全崩溃的算法。任何支持TLS 1.1、TLS 1.0或任何版本SSL的应用程序都会使数据面临销毁、更改和删除的风险。你必须禁用过时的TLS版本,否则你会把整个组织扔进绝望的深渊。

密码学家不断测试算法。发现密码算法中的缺陷会让密码学家感到高兴。当他们发现一种打破以前信任的算法的方法时,他们会非常高兴。即使您只使用当前的TLS版本,也可能需要禁用某些其他允许的算法。从历史上看,任何TLS版本都比它支持的一些算法更持久。假设当前的算法是牢不可破的,这是度过糟糕一天的好方法。

密码套件

在TLS术语中,密码套件(cipher suite)是特定对称、校验和和公钥算法的特定组合,以及各方可以加密和解密对方可以理解的消息所需的其他细节。它通常被称为 cipher

密码套件用于TLS客户端和服务器之间。它们对任何证书上使用的签名算法都没有影响,也不受其约束。

密码套件名称

每个密码套件都有一个由互联网号码分配机构(Internet Assigned Number Authority —— IANA)定义的正式名称,在他们的文档“传输层安全性(TLS)参数(Transport Layer Security (TLS) Parameters)”中。这些密码的名称类似于 TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384TLS_ECHE_ECDSA_WITH_ACHA20_POLY1305_SHA256 。您不需要知道每个密码套件的内部结构或了解底层算法,但必须注意不匹配。如果TLS连接的一端需要 TLS_AES_128_CCM_SHA256 ,而另一端坚持 TLS_AES_228_CCM_8_SHA256 时,中间额外的 _8_ 会让你感到悲伤。

TLS 1.2和1.3使用不同的语法来命名密码。TLS 1.2密码名称最多可以包含六条信息。

Protocol_Kx_Au_WITH_Enc_MAC

这个协议是 TLS

TLS 1.3从密码名称中删除了密钥交换和身份验证方法。密码套件不再规定它们。它还删除了WITH分隔符。名字要短得多:

Protocol_Enc_MAC

_WITH_ 的存在与否有助于识别TLS 1.3和1.2密码。此外,TLS 1.3标准仅包含五种密码。没有TLS 1.2密码幸存下来。

当您研究调试数据时,密码名称会立即识别您使用的TLS版本。

虽然密码套件设置了一大堆算法,但它们具有一定的灵活性。例如,密码 TLS_AES_128_GCM_SHA256 没有提到公钥算法,因此客户端和服务器可以协商。

切勿手动选择密码。本月最好的密码是下个月的噩梦。我们将在本章稍后的“密码列表”中了解如何使用最佳可用密码。

备用密码名

TLS软件开发人员一直是经典程序员错误的受害者,其中最著名的是认为,“我可以写出比这个广泛使用的schlock更好的东西”,但几乎同样众所周知的是“重命名已经有标准名称的东西”。如果你足够了解算法,可以为它们编写有用的代码,并了解密码将如何部署,那么将TLS_RSA_WITH_AES_256_CBC_SHA 简化为更短但仍然唯一的标识符(如 AES256-SHA )的冲动是可以理解的。

OpenSSL通过TLS 1.2为密码命名。在这方面,他们并不孤单。TLS 1.2密码的正式名称为 TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 ,在OpenSSL中称为 ECDHE-ECDSA-AES128-GCM-SHA256 ,而GnuTLS称之为 TLS_ECHE_ECDSA_AES_128_GCM_SHA256 。我承认连字符比下划线更容易输入。在许多密码名称中,_WITH_ 这个词并不能澄清任何事情,但在其他密码名称中它是一个重要的分隔符。然而,当算法不匹配导致混乱时,对同一密码套件使用不同的名称会导致不可避免的困惑。

我发现https://ciphersuite.info对于在不同名称之间进行翻译和识别算法的组件非常有用。这些网站还提供了关于算法当前强度的提示。

包括密码套件

使用 openssl ciphers 查看您的openssl构建所知道的密码套件,列出标准和OpenSSL名称。使用 -v 将每个密码单独列出,并附上详细信息。添加 -s 仅包含支持的密码。-stdname 标志显示标准名称。该表太宽,无法在本书的任何版本中轻松显示,因此我将使用 awk(1) 仅打印显示TLS 1.2的标准和OpenSSL名称的列。我发现 column -t 对于形成这样的输出非常宝贵。

或者,您可以使用 -V 代替 -v ,并在表的开头获取密码套件的十六进制值和官方名称,但这会改变您的 awk(1) 命令。

要在中等宽度的终端中获取有关密码的更多详细信息,请不要使用 -stdname 。你会得到六列。使用 column -t 可获得更清晰的输出。

第一列给出了此密码的OpenSSL名称。

第二列显示了引入此密码的TLS版本。您将看到似乎支持过时版本的TLS甚至SSL的密码。虽然SSLv3已经过时,但该版本中引入的密码仍在TLS 1.2中使用。您可以添加 -tls1_2-tls1_3 标志,仅列出特定版本TLS使用的密码。

Kx 列显示了密码的密钥交换算法。列出的前两个密码可以使用任何密钥交换算法,第三个必须使用RSA,第四个ECDH。

Au 列给出了密钥的身份验证算法。虽然前两个可以再次使用任何身份验证算法,但第三个使用RSA,第四个使用ECDSA。

TLS 1.3改变了密钥交换和身份验证的工作方式。它们不再是密码套件的一部分。这些密码显示的任何格式都是传统格式。

Enc 下,我们看到了对称加密算法。大多数现代密码使用AES的某种变体。

Mac (Message Authentication Code —— 消息身份验证码)提供了用于验证对称数据的算法。其中许多显示了AEAD,即带有关联数据的身份验证加密(Authenticated Encryption with Associated Data)。MAC被合并到加密方法中。GCM是部署最广泛的AEAD算法,它使用固定MAC算法。AES_128_GCM始终使用SHA256 MAC,而AES_256_GCM使用SHA384。我们的最后一个例子是一个非AEAD密码,它使用SHA256。

密码列表和密码排序

OpenSSL支持 cipher lists,允许您准确选择允许应用程序使用的密码。它包括各种名为HIGH、MEDIUM、RSA、ECDHE等的内置密码列表。 ciphers(1)openssl(1) 手册页包含内置列表的列表。也许最著名的是HIGH列表,它包含最强的密码套件。

密码列表限制了命令可以使用的密码。许多应用程序在其配置的某个地方接受密码列表。如果应用程序正在协商TLS连接,并且应该只使用RSA密码,则在应用程序中设置密码列表RSA可以实现这一点。

您可以通过在 openssl ciphers 命令中将列表名称作为最后一个参数来查看列表中的密码套件。这将命令限制为该列表中的密码。

假设你有一个客户,他的IT人员坚持认为你用来交换数据的应用程序只提供在伽罗瓦计数器模式(Galois Counter Mode)下使用AES的密码。这些策略注定会过时,就像FIPS一样,但它们会给你钱,所以你可以为它们提供一个专用的虚拟机并与之配合。查看手册页面会显示AESGCM密码列表。用它来展示你的客户会接受的算法。

如果你在互联网上充满HOWTO的火热沼泽中漫步,你会看到只使用HIGH密码列表中的密码的建议。在SSL的早期,这个列表至关重要,当时狂热的算法破解密码学家手中不断升级的计算能力意味着系统管理员需要不断更新他们的密码列表。几十年前,HIGH是一种方便的快捷方式,每当系统管理员更新OpenSSL时,它都会更新算法,而系统管理员不需要知道本周哪些算法被破坏的细节。

今天的HIGH列表包含所有TLS 1.2和1.3密码。如果你只运行现代TLS版本,你可能会认为你不需要在应用程序中设置密码列表。不过,新的密码将会出现。一些聪明的密码学家可能会破解我们认为可靠的算法。当这种情况发生时,OpenSSL会更新其密码列表。在配置中使用HIGH密码列表目前没有区别,但在每次OpenSSL升级时,都会自动通过应用程序堆栈传播更改。指定HIGH是一种主动防御。

如果教程建议更改密码列表,请检查日期。它可能已经过时了。

不过,允许的算法列表并不是唯一的因素。即使在HIGH密码列表中,一些算法也比其他算法好。OpenSSL的 cipher order 按强度对算法进行排名。TLS协议协商包括就密码达成一致。客户端声明它支持的每个算法。服务器会选择它最喜欢的一个。如果服务器只支持它认为强大的算法,它可以允许客户端选择算法。当客户端可能有硬件加密加速器时,这是有道理的。如果服务器支持各种强算法和弱算法,则服务器应尽可能使用最强的算法。

除非您有其他理由,否则请配置您的应用程序以支持HIGH密码列表和密码排序。

当HIGH不够用时

有些人认为HIGH密码列表是不够的。也许你的应用程序是一朵特别精致的花,你必须将你的密码列表限制在最好的算法上。我的第一个问题是:你会安排时间来监控加密算法的状态吗?当工作变得繁忙,你需要应对停机、经理和客户时,你会放下一切来调查不同算法的当前状态吗?您能否轻松测试更改并将其推送到所有服务器?您是否愿意处理老客户试图访问严格限制的密码列表所引起的问题?

现在你说了是的:你确定吗?真的超级确定吗?

如果是这样,Mozilla为许多流行的应用服务器提供了配置指南https://ssl-config.mozilla.org/,它只包括非常强的密码。每周检查这些配置的变化,可以很好地指导加密算法的当前状态。

从长远来看,我从未见过一个组织成功地管理这样严格限制的密码列表。如果你证明我错了,我完全没问题。就我个人而言,我坚持HIGH。

信任模型和证书颁发机构

公钥加密的最大问题是确定可信公钥的权威来源。您将找到两种信任公钥的通用模型,即信任网络和证书颁发机构。他们因谁来决定信任谁而有所不同。

OpenPGP推广的信任网络(Web of Trust)模型要求用户做出初始信任决策,然后用可传递的信任来评估世界。简而言之,“我选择信任密钥A,密钥A信任密钥B,密钥B信任信任信任D的C,所以我会信任D。”对于那些只想购买定制的六指手套而不想让数据包嗅探器窃取信用卡详细信息的最终用户来说,这是完全不合适的。

证书颁发机构(Certificate Authority —— CA)模型通过选择信任那些通过纠缠、贿赂、纠缠或勒索被认为值得信赖的组织,来避免让用户做任何信任工作。这些广受信任的证书颁发机构可以为我们其他人签署证书,并接受审计,以确保他们只签署有效的证书请求。它们是公共PKI的根基。

这两种模式都有问题。信任网令人困惑,难以使用,很容易被玩弄。正如任何民主国家所证明的那样,任何依赖于每个用户做出正确决策的系统都存在固有的缺陷。直到最近,权威的CA模式还很昂贵,并且依赖于CA完美地验证所有信息。正如任何技术官僚所证明的那样,任何依赖精英做出重要决定的制度都存在固有的缺陷。唯一明智的做法是假装安全存在,躲在20世纪80年代令人宽慰的幻想电影中。

SSL和TLS旨在将人们与他们的钱分开,而“用户易用性”是此类协议的决定因素。用户易用性需要信任。证书颁发机构模型成为SSLv2的标准。

即使在CA模型下,也不是所有设备和应用程序都信任相同的证书颁发机构。我们将在第3章讨论信任包。

自动证书管理环境(Automated Certificate Management Environment —— ACME)的出现意味着可以免费获得常规X.509证书。

私钥保护

任何能够读取一对私钥的人都可以使用该密钥的证书伪装成密钥所有者。如果我有一个TLS证书,可以权威地将我的网站标识为https://mwl.io,任何获得私钥的人都可以设置一个冒充我网站的流氓网络服务器。(任何能够说服CA为该域签署证书的人也可以这样做,但这是一种不同的攻击。)证书文件必须只能由root和使用证书的应用程序读取。除了root之外,任何人都不应该写它们。

如果有人默许访问私钥,整个证书将被泄露,不再可信。您必须撤销证书并生成新证书。

默认情况下,私钥文件使用密码进行加密。除非有人键入密码,否则无法使用密钥,这使得私钥文件对没有密码的入侵者毫无用处。缺点是,在人类键入密码之前,密钥不会激活。服务器重新启动?TLS服务将关闭,直到有人键入密码。您的服务器是否有操作员日夜待命?你们的员工全天都准备好了吗?你相信那些有密码的工作人员吗?大多数员工有限的小公司(以及许多大公司)认为密码是不可行的。

如果您的环境确实需要保护其私钥,请考虑将私钥放在硬件安全模块(hardware security module —— HSM)上。访问私钥意味着拥有物理设备,这可能会失败。作为昂贵的HSM和基本Unix之间的中间步骤,您可能会使用支持广泛权限分离的应用程序和操作系统,如OpenBSD。

加密您的私钥并非不可逆转(除非您丢失了密码)。如果您尝试使用加密的私钥,发现您的组织无法处理它,请创建一个未加密的私钥文件,如第3章所示,或安装HSM。

TLS恢复

密码学不仅复杂,数学也乏味、可恶且昂贵。每次连接开始时的初始公钥计算都会消耗CPU周期。如果我们能在客户端点击网页的下一个链接或新邮件检查时重用初始证书验证和协议协商,那就太好了。

恢复允许TLS客户端从停止的地方继续。您第一次单击网站时,客户端和服务器会执行完整的TLS验证和协商。不过,第二次点击后,客户端将恢复之前的TLS会话,并保存一轮网络请求和公钥计算。恢复提高了TLS封装协议对后续请求的响应速度,特别适用于一个“会话”涉及许多连接的交互式应用程序,如web。

基于TLS 1.2及更早版本的客户端会话票证(session tickets)和服务器端会话缓存(session caches)的恢复。两者都有类似的问题。TLS 1.2会话票证是唯一标识特定客户端的数据块。该票证包含有关密码预共享密钥(pre-shared key —— PSK)的足够信息,以识别会话、导出密钥并使用相同的设置启动新连接。这种恢复形式很容易被打破,不应该使用。

TLS 1.3放弃了早期的恢复方法,转而采用预共享密钥(PSK)系统。它仍然使用会话票证,但以更严格的方式。到目前为止,它仍然完好无损。

无论TLS版本如何,恢复(resumption)都会给客户端带来隐私风险。服务器可以通过票和PSK唯一地识别和跟踪浏览器。这对服务器运营商来说不是问题;我们精确地使用TLS证书,这样客户端就可以唯一地识别我们!然而,对隐私敏感的用户可能希望在客户端禁用TLS恢复。负载均衡器和其他网络设备使恢复更加复杂。它可能在任何给定的环境中工作,也可能不工作。

完全正向保密

当你的所有数据都用你的私钥加密时,任何拥有密钥的人都可以捕获和解密你的数据。这是一场TLS噩梦。但是,如果入侵者在传输过程中捕获并保存了您的数据,然后窃取了您的私钥呢?事情已经发生了。

许多TLS 1.2和更早的密码在密钥交换和身份验证中都使用证书的RSA密钥进行身份验证。如果你有私钥和保存的数据包捕获,你就可以很容易地解密会话。流行的数据包嗅探器包括一个“指向我你的私钥(point me at your private key)”文件,正是为了这个目的。

Diffie-Hellman瞬时密钥交换(Diffie-Hellman Ephemeral Key Exchange —— DHE)算法让我们避免使用证书的密钥。椭圆曲线(Elliptic curve —— ECDHE)版本紧随其后。这些密码不使用证书的RSA密钥来商定对称密钥。无法解密捕获的数据包跟踪。这被称为完美前向保密(Perfect Forward Secrecy ——PFS)。尽管名字叫“完美前向保密”,但它并不完美。从来没有加密解决方案是完美的。

在所有TLS 1.3密码和一些TLS 1.2密码中,密钥交换现在使用ECDHE或DHE等临时密钥交换算法。

如果您已经可以访问客户端或服务器,并且可以配置临时密钥日志文件来捕获主密钥,则可以实时解密TLS 1.3会话。TLS不是为了防止此类调试。

服务器名称指示

一个IP地址可以承载许多网站。当客户端连接到TLS封装的网站时,web服务器需要知道客户端试图连接到哪个网站。HTTP 1.1协议在连接建立后给出网站名称。当目标站点尚未被识别时,如何告诉web服务器使用哪个证书来加密连接?

答案是服务器名称指示(Server Name Indication —— SNI)。客户端在初始TLS协商中包括目标站点。服务器使用SNI的提示建立连接,然后让HTTP发出单独的请求。不支持SNI的服务器每个IP地址只能支持一个TLS站点。

即使在TLS 1.3中,SNI也是少数仍以明文形式发送的连接部分之一。窃听器可以告诉你正在访问哪个网站。人们正在研究加密的SNI(encrypted SNI——ESNI),但还没有最终确定。

有了这个基础,让我们在整个网络中使用TLS。