SSL 是如何工作的?我刚刚意识到我们实际上并没有明确的答案,这是值得一提的。
我想查看以下方面的详细信息:
- 协议的高级描述。
- 密钥交换的工作原理。
- 如何执行真实性、完整性和机密性。
- 拥有 CA 的目的是什么,以及它们如何颁发证书。
- 所涉及的任何重要技术和标准(例如 PKCS)的详细信息。
SSL 是如何工作的?我刚刚意识到我们实际上并没有明确的答案,这是值得一提的。
我想查看以下方面的详细信息:
SSL(及其后继者TLS)是一种直接在 TCP 之上运行的协议(尽管也有基于数据报的协议的实现,例如 UDP)。这样,更高层的协议(例如 HTTP)可以保持不变,同时仍提供安全连接。在 SSL 层之下,HTTP 与 HTTPS 相同。
当正确使用 SSL/TLS 时,攻击者可以在电缆上看到的只是你连接的 IP 和端口、大致发送了多少数据以及使用了哪些加密和压缩。他也可以终止连接,但双方都会知道连接已被第三方中断。
在典型的使用中,攻击者还能够找出你正在连接的主机名(但不是 URL 的其余部分):虽然 HTTPS 本身不会暴露主机名,但你的浏览器通常需要先发出 DNS 请求找出将请求发送到的 IP 地址。
建立 TCP 连接后,客户端启动 SSL 握手。客户端(可以是浏览器以及任何其他程序,例如 Windows Update 或 PuTTY)发送许多规范:
服务器识别它和客户端都支持的最高 SSL/TLS 版本,从客户端的一个选项中选择一个密码套件(如果它支持一个),并且可以选择一种压缩方法。
在此基本设置完成后,服务器发送其证书。此证书必须由客户端本身或客户端信任的一方信任。例如,如果客户端信任 GeoTrust,则客户端可以信任来自 Google.com 的证书,因为 GeoTrust 以加密方式签署了Google 的证书。
在验证了证书并确定该服务器确实是他声称的人(而不是中间人)之后,交换了一个密钥。这可以是一个公钥、一个“PreMasterSecret”或者什么都不是,这取决于所选择的密码套件。服务器和客户端现在都可以计算对称加密的密钥,为什么不能 PKE?. 客户端告诉服务器,从现在开始,所有的通信都将被加密,并向服务器发送一个经过加密和认证的消息。
服务器验证 MAC(用于身份验证)是否正确以及消息可以正确解密。然后它返回一条消息,客户端也会验证该消息。
握手现已完成,两台主机可以安全通信。有关详细信息,请参阅technet.microsoft.com/en-us/library/cc785811和en.wikipedia.org/wiki/Secure_Sockets_Layer。
要关闭连接,使用 close_notify 'alert'。如果攻击者试图通过完成 TCP 连接(注入 FIN 数据包)来终止连接,双方都会知道连接被不正确地终止。但是,连接不会因此而受到损害,只会中断。
一个网站想要安全地与您通信。为了证明其身份并确保它不是攻击者,您必须拥有服务器的公钥。但是,您几乎无法存储地球上所有网站的所有密钥,数据库将非常庞大,并且必须每小时运行一次!
对此的解决方案是证书颁发机构,简称 CA。当您安装操作系统或浏览器时,可能会附带一份受信任的 CA 列表。这个列表可以随意修改;您可以删除您不信任的人,添加其他人,甚至创建自己的 CA(尽管您将是唯一信任此 CA 的人,因此它对公共网站没有多大用处)。在这个 CA 列表中,还存储了 CA 的公钥。
当 Google 的服务器向您发送其证书时,它还提到它是由 GeoTrust 签名的。如果您信任 GeoTrust,您可以验证(使用 GeoTrust 的公钥)GeoTrust 确实签署了服务器的证书。要自己签署证书,您需要只有 GeoTrust 知道的私钥。这样,攻击者就不能自己签署证书并错误地声称自己是 Google.com。如果证书被修改了一位,签名将不正确,客户端将拒绝它。
那么如果我知道公钥,服务器可以证明它的身份吗?是的。通常,公钥加密,私钥解密。用服务器的公钥加密一条消息,发送出去,如果服务器能重复回原来的消息,就证明它在不泄露密钥的情况下得到了私钥。
这就是为什么能够信任公钥如此重要的原因:任何人都可以生成私钥/公钥对,也可以是攻击者。您不想最终使用攻击者的公钥!
如果您信任的 CA 之一遭到破坏,攻击者可以使用被盗的私钥为他们喜欢的任何网站签署证书。当攻击者可以向您的客户发送伪造的证书时,该证书由您自己使用您信任的 CA 的私钥签名,您的客户不知道公钥是伪造的,使用被盗的私钥签名。
但是 CA 可以让我信任他们想要的任何服务器!是的,这就是信任的来源。您必须相信 CA 不会随心所欲地制作证书。但是,当 Microsoft、Apple 和 Mozilla 等组织信任 CA 时,CA 必须进行审计;另一个组织定期检查它们,以确保一切仍在按照规则运行。
当且仅当注册人可以证明他们拥有为其颁发证书的域时,才会颁发证书。
这个用于消息认证的 MAC 是什么?每条消息都使用所谓的消息验证码或简称为 MAC 进行签名。如果我们就密钥和散列密码达成一致,您可以验证我的消息来自我,我可以验证您的消息来自您。
例如,使用“正确的马电池订书钉”键和消息“示例”,我可以计算 MAC“58393”。当我将此带有 MAC 的消息发送给您时(您已经知道密钥),您可以执行相同的计算并将计算的 MAC 与我发送的 MAC 匹配。
攻击者可以修改消息但不知道密钥。他无法计算出正确的 MAC,您就会知道该消息不是真实的。
通过在计算 MAC 时包含序列号,可以消除重放攻击。SSL 做到了这一点。
您说客户端发送一个密钥,然后用于设置对称加密。是什么阻止了攻击者使用它?服务器的公钥可以。由于我们已经验证了公钥确实属于服务器而不属于其他任何人,因此我们可以使用公钥对密钥进行加密。当服务器收到此信息时,他可以使用私钥对其进行解密。当其他人收到它时,他们无法解密它。
这也是密钥大小很重要的原因:公钥和私钥越大,破解客户端发送给服务器的密钥就越困难。
总结:
另请参阅:Ivan Ristic 的具有许多针对 SSL 的攻击向量的方案 (png)
详细:
没有简单直接的方法;正确完成后,SSL 是安全的。如果用户忽略证书警告,攻击者可以尝试,这会立即破坏安全性。当用户这样做时,攻击者不需要来自 CA 的私钥来伪造证书,他只需发送自己的证书。
另一种方法是应用程序中的缺陷(服务器端或客户端)。一个简单的例子是网站:如果网站使用的资源之一(例如图像或脚本)通过 HTTP 加载,则无法再保证机密性。即使浏览器在从安全页面请求非安全资源时不发送 HTTP Referer 标头(来源),窃听交通的人仍然有可能猜测您从哪里访问;例如,如果他们知道图像 X、Y 和 Z 在一个页面上使用,当他们看到您的浏览器同时请求这三个图像时,他们可以猜测您正在访问该页面。此外,在加载 Javascript 时,整个页面可能会受到影响。攻击者可以在页面上执行任何脚本,例如修改银行交易的对象。
发生这种情况时(通过 HTTP 加载资源),浏览器会发出混合内容警告:Chrome、Firefox、Internet Explorer 9
HTTP 的另一个技巧是当登录页面不安全时,它会提交到 https 页面。“太好了,”开发人员可能想,“现在我节省了服务器负载,密码仍然是加密发送的!” 问题在于sslstrip,这是一个修改不安全登录页面的工具,以便将其提交到某个地方,以便攻击者可以读取它。
过去几年也出现了各种攻击,例如TLS 重新协商漏洞、sslsniff、BEAST,以及最近的CRIME。但是,所有常见的浏览器都受到保护,免受所有这些攻击,因此如果您运行的是最新的浏览器,这些漏洞是没有风险的。
最后但并非最不重要的一点是,您可以诉诸其他方法来获取 SSL 拒绝您获取的信息。如果您已经可以看到并篡改用户的连接,那么用键盘记录器替换他/她的 .exe 下载文件或简单地对该人进行物理攻击可能并不难。密码学可能相当安全,但人为和人为错误仍然是一个薄弱因素。根据Verizon 的这篇论文,10% 的数据泄露涉及物理攻击(请参见第 3 页),因此一定要牢记这一点。
由于 SSL 的一般概念已经涉及到其他一些问题(例如this one和that one),所以这次我将详细介绍。细节很重要。这个答案会有点冗长。
SSL 是一个历史悠久且有多个版本的协议。第一个原型来自 Netscape,当时他们正在开发他们的旗舰浏览器Netscape Navigator的第一个版本(这个浏览器在浏览器大战的早期扼杀了Mosaic ,尽管有新的竞争对手,浏览器大战仍在肆虐)。版本 1 从未公开,所以我们不知道它的样子。SSL 版本 2 在草稿中进行了描述,可以在那里阅读;它有许多弱点,其中一些相当严重,因此它已被弃用,较新的 SSL/TLS 实现不支持它(而较旧的默认禁用)。除了偶尔作为参考外,我不会再谈论 SSL 版本 2。
SSL 版本 3(我将其称为“SSLv3”)是一种增强型协议,至今仍然有效并得到广泛支持。尽管仍然是 Netscape Communications(或现在拥有它的人)的财产,但该协议已作为“历史 RFC”(RFC 6101)发布。同时,该协议已经标准化,为避免法律问题使用了新名称;新名称是TLS。
到目前为止,已经产生了三个版本的 TLS,每个版本都有其专用的 RFC:TLS 1.0、TLS 1.1和TLS 1.2。它们在内部非常相似,并且与 SSLv3 非常相似,以至于实现可以轻松支持 SSLv3 和所有三个 TLS 版本,至少 95% 的代码是通用的。尽管如此,在内部,所有版本都由带有major.minor的版本号指定格式; SSLv3 是 3.0,而 TLS 版本分别是 3.1、3.2 和 3.3。因此,难怪 TLS 1.0 有时被称为 SSL 3.1(这也不对)。SSL 3.0 和 TLS 1.0 仅在一些细节上有所不同。TLS 1.1 和 1.2 尚未得到广泛支持,尽管由于可能存在弱点(见下文“BEAST 攻击”),这有其推动力。SSLv3 和 TLS 1.0 “无处不在”受支持(甚至 IE 6.0 都知道它们)。
SSL 旨在为任意数据提供安全的双向隧道。以TCP为例,它是通过 Internet 发送数据的著名协议。TCP 在 IP“数据包”上工作,并为字节提供双向隧道;它适用于每个字节值并将它们发送到可以同时操作的两个流中。TCP 处理将数据拆分为数据包、确认它们、将它们重新组合回正确顺序的艰巨工作,同时删除重复数据并重新发送丢失的数据包。从使用 TCP 的应用程序的角度来看,只有两个流,数据包是不可见的;特别是,流不会被拆分为“消息”(如果它希望有消息,则由应用程序采用自己的编码规则,并且那个' 做)。
TCP 在出现“意外”时是可靠的,即由于硬件不稳定、网络拥塞、智能手机用户走出给定基站范围以及其他非恶意事件导致的传输错误。但是,对传输介质有一定访问权限的恶意个人(“攻击者”)可以读取所有传输的数据和/或故意更改它,而 TCP 无法防止这种情况发生。因此 SSL。
SSL假设它通过类似 TCP 的协议工作,该协议提供可靠的流;SSL 不实现丢失数据包的重新发送和类似的事情。攻击者应该有权以不可避免的方式完全破坏通信(例如,他可以切断电缆),因此 SSL 的工作是:
SSL 在很大程度上(但不是绝对)实现了这些目标。
SSL是分层的,底层是记录协议。在 SSL 隧道中发送的任何数据都会分成记录。通过网络(底层 TCP 套接字或类似 TCP 的介质),记录如下所示:
HH
V1:V2
L1:L2
数据
在哪里:
HH
是单个字节,指示记录中的数据类型。定义了四种类型:change_cipher_spec (20)、alert (21)、handshake (22) 和application_data (23)。V1: V2
是协议版本,超过两个字节。对于当前定义的所有版本,V1
其值为 0x03,而V2
SSLv3 的值为 0x00,TLS 1.0 的值为 0x01,TLS 1.1 的值为 0x02,TLS 1.2 的值为 0x03。L1: L2
是 的长度data
,以字节为单位(使用大端约定:长度为 256*L1+L2)。的总长度data
不能超过 18432 字节,但实际上,它甚至无法达到该值。所以一条记录有一个 5 字节的头部,后面跟着最多 18 kB 的数据。这data
是应用对称加密和完整性检查的地方。当发送记录时,发送者和接收者都应该就当前应用哪些加密算法以及使用哪些密钥达成一致;该协议是通过握手协议获得的,将在下一节中介绍。压缩,如果有的话,也应用在那个点上。
详细地说,记录的建立是这样的:
MAC 通常是具有常用哈希函数之一的HMAC(主要是 MD5、SHA-1 或 SHA-256)(对于 SSLv3,这不是“真正的”HMAC,而是非常相似的东西,据我们所知,与 HMAC 一样安全)。加密将使用CBC 模式中的分组密码或RC4流密码。请注意,理论上,可以采用其他类型的模式或算法,例如,结合加密和完整性检查的这些漂亮模式之一;甚至还有一些 RFC。但在实践中,部署的实现还不知道这些,所以他们使用 HMAC 和 CBC。至关重要的是,首先计算 MAC 并将其附加到数据中,然后对结果进行加密。这是 MAC-then-encrypt 并且实际上是不是一个很好的主意。MAC 是通过(压缩的)有效负载和序列号的串联计算的,因此勤奋的攻击者可能不会交换记录。
握手是在记录协议中播放的协议。它的目标是建立用于记录的算法和密钥。它由消息组成。每个握手消息都以一个四字节的头开始,一个字节描述消息类型,然后是三个字节的消息长度(大端约定)。然后发送连续的握手消息,并带有标记为“握手”类型的记录(每个记录的标头的第一个字节的值为 22)。
注意层:握手消息,完整的四字节头,然后作为记录发送,每条记录也有自己的头。此外,可以在同一记录中发送多个握手消息,并且可以将给定的握手消息拆分为多个记录。从构建握手消息的模块的角度来看,“记录”只是一个可以发送字节的流;它忽略了该流的实际拆分为记录。
最初,客户端和服务器“同意”无 MAC 和空压缩的空加密。这意味着他们将首先发送的记录将以明文形式发送且不受保护。
握手的第一条消息是ClientHello
. 客户端通过该消息表明其打算执行某些 SSL。注意“客户”是一个象征性的角色;它的意思是“首先发言的一方”。碰巧在 HTTPS 上下文中,即 HTTP-within-SSL-within-TCP,所有三层都有“客户端”和“服务器”的概念,并且它们都同意(TCP 客户端也是 SSL 客户端和HTTP 客户端),但这是一种巧合。
该ClientHello
消息包含:
密码套件是一组密码算法的 16 位符号标识符。例如,TLS_RSA_WITH_AES_128_CBC_SHA
密码套件的值为 0x002F,表示“记录使用 HMAC/SHA-1 和 AES 加密以及 128 位密钥,并且密钥交换是通过使用服务器的 RSA 公钥加密随机密钥来完成的”。
服务器响应ClientHello
一个ServerHello
包含:
完整的握手如下所示:
Client Server
ClientHello -------->
ServerHello
Certificate*
ServerKeyExchange*
CertificateRequest*
<-------- ServerHelloDone
Certificate*
ClientKeyExchange
CertificateVerify*
[ChangeCipherSpec]
Finished -------->
[ChangeCipherSpec]
<-------- Finished
Application Data <-------> Application Data
(这个模式是从 RFC 中无耻地复制过来的。)
我们看到ClientHello
和ServerHello
。然后,服务器发送一些其他消息,这些消息取决于密码套件和其他一些参数:
然后客户端必须响应:
Certificate
带有空证书列表的消息)。然后客户端发送一个ChangeCipherSpec消息,它不是握手消息:它有自己的记录类型,所以会在自己的记录中发送。它的内容是纯符号的(值 1 的单个字节)。此消息标记客户端切换到新协商的密码套件和密钥的点。来自客户端的后续记录将被加密。
Finished消息是对所有先前的握手消息(来自客户端和服务器)计算的加密校验和。由于它是在 之后发出的ChangeCipherSpec
,因此它也被完整性检查和加密所覆盖。当服务器接收到该消息并验证其内容时,它会获得一个证明,证明它确实一直在与同一个客户端进行通信。此消息保护握手不被更改(攻击者无法修改握手消息并仍然获得Finished
正确的消息)。
服务器最终以自己的ChangeCipherSpec
then响应Finished
。此时,握手完成,客户端和服务器可以交换应用程序数据(在这样标记的加密记录中)。
要记住:客户端建议但服务器选择. 密码套件在服务器手中。礼貌的服务器应该遵循客户端的偏好(如果可能的话),但他们可以不这样做,有些实际上会这样做(例如,作为对 BEAST 的保护的一部分)。
在完整的握手中,服务器向客户端发送一个“会话 ID”(即一组最多 32 个字节)。稍后,客户端可以返回并发送相同的会话 ID 作为其ClientHello
. 这意味着客户端仍然记得上次握手的密码套件和密钥,并希望重用这些参数。如果服务器还记得密码套件和密钥,那么它会将特定的会话 ID 复制到其ServerHello
中,然后遵循缩写的握手:
Client Server
ClientHello -------->
ServerHello
[ChangeCipherSpec]
<-------- Finished
[ChangeCipherSpec]
Finished -------->
Application Data <-------> Application Data
缩写的握手更短:消息更少,没有非对称加密业务,最重要的是减少了延迟。Web 浏览器和服务器经常这样做。典型的 Web 浏览器会打开一个完整握手的 SSL 连接,然后对与同一服务器的所有其他连接进行简短的握手:它并行打开的其他连接,以及与同一服务器的后续连接。实际上,典型的 Web 服务器会在 15 秒不活动后关闭连接,但它们会记住会话(密码套件和密钥)更长的时间(可能数小时甚至数天)。
SSL 可以使用多种密钥交换算法。这是由密码套件指定的;每个密钥交换算法都适用于某些类型的服务器公钥。最常见的密钥交换算法有:
RSA
: 服务器的密钥是 RSA 类型的。客户端生成一个随机值(48 个字节的“pre-master secret”,其中 46 个是随机的)并使用服务器的公钥对其进行加密。没有ServerKeyExchange
。DHE_RSA
:服务器的密钥是 RSA 类型的,但仅用于签名。实际的密钥交换使用 Diffie-Hellman。服务器发送一条ServerKeyExchange
消息,其中包含 DH 参数(模数、生成器)和新生成的 DH 公钥;此外,服务器签署此消息。客户端将响应一条ClientKeyExchange
消息,其中还包含一个新生成的 DH 公钥。DH 产生“预主密钥”。DHE_DSS
: 类似DHE_RSA
,但服务器有一个 DSS 密钥(“DSS”也称为“DSA”)。DSS 是一种仅签名算法。不太常用的密钥交换算法包括:
DH
:服务器的密钥是 Diffie-Hellman 类型的(我们说的是包含 DH 密钥的证书)。当 RSA 专利仍然有效时(这是在上个世纪),这曾经以行政方式“流行”(美国联邦政府强制使用)。尽管有官僚主义的推动,但它从未像 RSA 那样广泛部署。DH_anon
:像DHE
套件,但没有来自服务器的签名。这是一个无证书密码套件。通过构造,它很容易受到中间人攻击,因此很少启用。PSK
:预共享密钥密码套件。仅对称密钥交换,建立在预先建立的共享秘密之上。SRP
:SRP 协议的应用,它是一种密码验证密钥交换协议。客户端和服务器根据共享密钥相互验证,共享密钥可以是低熵密码(而 PSK 需要高熵共享密钥)。非常漂亮。尚未得到广泛支持。DHE
与新生成的 RSA 密钥对类似。由于生成 RSA 密钥的成本很高,因此这不是一个流行的选项,并且仅被指定为“出口”密码套件的一部分,该套件符合 2000 年前美国关于密码学的出口法规(即最多 512 位的 RSA 密钥)。现在没有人这样做。DH*
算法的变体。很时尚。将来应该会变得普遍。数字证书是非对称密钥的容器。它们旨在解决密钥分配问题。即,客户端想要使用服务器的公钥。攻击者会尝试让客户端使用攻击者的公钥。所以客户端必须有办法确保它使用正确的密钥。
SSL 应该使用X.509。这是证书的标准。每个证书都由证书颁发机构签署。这个想法是客户端天生就知道少数 CA 的公钥(这些是“信任锚”或“根证书”)。使用这些密钥,客户端可以验证CA 在已颁发给服务器的证书上计算的签名。这个过程可以递归扩展:一个 CA 可以为另一个 CA 颁发证书(即签署包含其他 CA 名称和密钥的证书结构)。以根 CA 开始并以服务器证书结束的证书链,中间有中间 CA 证书,每个证书都相对于在前一个证书中编码的公钥进行签名,令人难以置信地称为证书链。
因此,客户端应该执行以下操作:
Certificate
消息应该准确地包含这样一个链。带有 X.509 证书的认证模式经常受到批评,这并不是出于技术原因,而是出于政治经济原因。它将验证权集中在少数玩家手中,这些玩家不一定是好心的,或者至少并不总是有能力的。不时会发布其他系统的提案(例如Convergence或DNSSEC),但没有一个(尚未)获得广泛接受。
对于基于证书的客户端身份验证,完全由服务器决定如何处理客户端证书(以及如何处理拒绝发送证书的客户端)。在 Windows/IIS/Active Directory 世界中,客户端证书应包含作为“用户主体名称”的帐户名称(在证书的主题替代名称扩展中编码);服务器在其 Active Directory 服务器中查找它。
由于握手只是一些使用当前加密/压缩约定作为记录发送的消息,因此理论上没有什么可以阻止 SSL 客户端和服务器在已建立的 SSL 连接中进行第二次握手。而且,确实,它得到了支持,并且在实践中发生了。
在任何时候,客户端或服务器都可以发起新的握手(服务器可以发送HelloRequest
消息来触发它;客户端只是发送一个ClientHello
)。一个典型的情况如下:
我刚才描述的情况有一个有趣的弱点;有关解决方法,请参阅RFC 5746。从概念上讲,SSL 仅以“前向”方式传输安全特性。当进行新的握手时,在新握手之前可以知道的关于客户端的任何信息在之后仍然有效(例如,如果客户端在隧道内发送了一个好的用户名+密码),但反之则不然。在上述情况下,之前收到的第一个 HTTP 请求第二次握手的基于证书的身份验证不涵盖新的握手,它会被攻击者选择!不幸的是,一些 Web 服务器只是假设来自第二次握手的客户端身份验证扩展到第二次握手之前发送的内容,并且它允许攻击者使用一些讨厌的技巧。RFC 5746 试图解决这个问题。
警报消息只是警告和错误消息。它们相当无趣,除非它们可以被某些攻击破坏(见下文)。
有一个重要的警报消息,称为close_notify
:它是客户端或服务器希望关闭连接时发送的消息。收到此消息后,服务器或客户端也必须以 a 响应,close_notify
然后认为隧道已关闭(但会话仍然有效,并且可以在别有用心的简短握手中重用)。有趣的是,这些警报消息与所有其他记录一样,受到加密和 MAC 的保护。因此,连接闭包被密码保护伞覆盖。
这在(旧)HTTP 的上下文中很重要,其中一些数据可以由服务器发送而无需明确的“内容长度”:数据延伸到传输流的末尾。close_notify
带有SSLv2的旧 HTTP(没有 因此,攻击者可以在不被捕获的情况下截断数据。这是 SSLv2 的问题之一(可以说是最糟糕的),SSLv3 修复了它。请注意,“现代”HTTP 使用“Content-Length”标头和/或分块编码,即使 SSL 层允许,它也不容易受到这种截断的影响。不过,很高兴知道 SSL 提供了对关闭事件的保护。
Stack Exchange 答案长度是有限制的,所以对 SSL 的一些攻击的描述将在另一个答案中(另外,我还有一些煎饼要煮)。敬请关注。
在上一个答案中对 SSL 进行了冗长的介绍之后,让我们来看看有趣的东西,即:
有很多针对 SSL 的攻击,有些是基于实现错误,有些是基于真正的协议弱点。
必须记住,虽然 SSL 是最受攻击的协议之一(因为它非常引人注目:在一篇研究文章的摘要中,成功的 SSL 应用看起来非常漂亮),但 SSL 也是修复最多的协议之一。它被认为是健壮的,因为所有已知的攻击传输协议的方法都已在 SSL 上进行过尝试,并且 SSL 已在适当的地方进行了修补。
在 SSLv3 的早期,SSLv2 仍然被广泛使用,因此客户端普遍发送 SSLv2 兼容ClientHello
消息,这仅表明也支持 SSLv3;然后,服务器将接受提示并以 SSLv3+ 方言响应(有关详细信息,请参阅RFC 2246的附录 E)。由于 SSLv2 存在弱点,攻击者最好安排一个都知道 SSLv3 的客户端和服务器使用 SSLv2 相互通信。这称为版本回滚攻击。该概念也正式扩展到更高版本。
添加了 Kludges 以检测回滚尝试。对于回滚到 SSLv2 的回滚,知道 SSLv3+ 的客户端应该为 RSA 加密步骤使用特殊填充(SSLv2 仅支持基于 RSA 的密钥交换):在PKCS#1 中,要加密的数据应该是用一些随机字节填充;一个支持 SSLv3 的客户端应该将最后 8 个填充字节中的每一个都设置为固定值 0x03。然后服务器检查这些字节;如果找到了 8 个 0x03,则很可能会尝试回滚,并且服务器会拒绝该尝试(仅 SSLv2 的客户端由于完全缺乏运气而使用此类填充字节的概率只有 255 -8,因此误报发生在微不足道的比率)。
为了回滚到旧版本的 SSL/TLS,但不早于 SSLv3,添加了另一个 kludge:在客户端使用服务器的 RSA 密钥加密的 48 个字节的pre-master secret中,前两个字节不是随机的,而是应该等于客户端首先在其ClientHello
消息中写入的“最大支持的协议版本”。不幸的是,一些客户端弄错了,而且这种组合只适用于基于 RSA 的密钥交换,因此对回滚的保护非常有限。幸运的是,SSLv3+ 有另一个更强大的防止回滚的保护,那就是握手消息被散列在一起,当Finished
消息被构建。这可以防止回滚,除非“旧版本”非常弱,以至于攻击者可以在握手本身结束之前完全破坏整个加密。这还没有发生(SSLv3 仍然相当健壮)。
一些标准密码套件在某种程度上是故意的。有:
TLS_RSA_WITH_NULL_SHA
;TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5
(旨在遵守上世纪美国严格的出口规则的密码套件——这些规定在比尔克林顿时代结束时大部分已被取消);TLS_RSA_WITH_DES_CBC_SHA
. 56 位 DES 可以用现有技术破解,但这对于业余爱好者(即使是一个可以使用几百台大学机器的无聊学生)来说仍然有点困难,所以我倾向于将 56 位 DES 称为“中等强度”。这为版本回滚攻击的变体开辟了道路,其中攻击者强制客户端和服务器就弱密码套件达成一致,其想法是攻击者修改客户端宣布的密码套件列表。如果选择的密码套件太弱以至于他可以破解它以重新计算明显正确的Finished
消息,这对攻击者来说是可行的。实际上,SSLv3+ 中使用的 MAC(即使基于 MD5)足够强大,可以防止这种情况发生。所以这里没有真正的担心。此外,我认为这里的任何真正弱点是客户端或服务器完全接受使用弱密码套件。
默认情况下,现代 Web 浏览器不允许使用这种弱密码套件。
如果 SSL 连接使用 RSA 密钥交换,并且攻击者保留了记录的副本,然后稍后(可能几个月后,可能通过检查废弃硬盘或磁带上的所有备份)获得了私钥的副本,那么他可以解开握手并解密数据。
完美的前向保密是关于“稍后”的反击。您可以通过使用DHE
密码套件来获得它。使用 DHE 密码套件,可用于解开握手的实际私钥是临时 Diffie-Hellman 密钥,而不是服务器的 RSA(或 DSS)私钥。由于是短暂的,它只存在于 RAM 中,从未写入硬盘;因此,它应该更能抵御不可告人的盗窃。
所以教训是:作为一项规则,如果可能,请尝试使用 DHE 密码套件。你仍然应该注意你的备份,不要让你的私钥泄漏,但是,至少,DHE 套件使这种泄漏问题不那么严重,特别是如果它发生在密钥生命周期结束之后(即相应的证书不是有效期更长)。
整个证书业务是 SSL 的痛处。
从技术上讲,SSL 完全独立于 X.509。证书链作为不透明的 blob 进行交换。在某些时候,客户端必须使用服务器的公钥,但客户端可以自由地以它认为合适的任何方式“知道”该密钥。在某些可以使用 SSL 的特定场景中,客户端已经知道服务器的公钥(在代码中硬编码),而只是忽略服务器发送的证书。然而,在 HTTPS 的常见情况下,客户端会按照X.509中的描述验证服务器的证书链(以牺牲您的理智为代价阅读它;您已被警告过)。
这会产生许多攻击向量,例如:
验证需要验证证书在当前日期仍然有效。客户端机器如何知道当前日期?使用它的内部时钟,并且可能通过与NTP 服务器交谈(以一种完全不受保护的方式!)。客户端可能会关闭几分钟、几小时、几天甚至几年(我见过),并且在某种程度上,强大的攻击者可以通过摆弄 NTP 消息来强制它。这将允许攻击者使用多年前已被吊销的过时证书。注意一个有趣的事实:SSL“客户端随机”和“服务器随机”应该包含 28 个随机字节和本地日期和时间(超过 4 个字节)。包含时间的目的是作为针对基于时间的攻击的解决方法的一部分。我不知道任何真正检查它的实现。
直到大约 2003 年,Internet Explorer / Windows 中证书验证的实现并没有正确处理“基本约束”扩展。最终效果是任何拥有 100 欧元证书的人都可以充当 CA,并使用任意选择的名称和密钥颁发“证书”。
X.509 包含一个称为撤销的损害遏制功能:这是关于发布一个被驱逐的证书列表,从密码学角度看,这些证书看起来不错,但不应该被信任(例如,它们的私钥被盗,或者它们包含错误的名称)。撤销仅在相关方(即浏览器)接受下载庞大的撤销列表(可能有几兆字节长!)或联系OCSP 服务器时才有效。现代浏览器现在这样做了,但有点不情愿,如果他们不能及时获得撤销状态信息,许多人会接受连接(因为人类用户没有耐心)。多年来,总体情况有所改善,但速度相当缓慢。
一些根 CA 在过去确实犯了一些错误(例如 Comodo 和 DigiNotar)。这导致了伪造证书的颁发(名称是www.microsoft.com
,但私钥根本不在 Microsoft 手中......)。这些错误被发现,证书被吊销,但它仍然提出了一些令人不安的问题(例如,是否有其他 CA 有这些问题但没有透露它们,或者更糟糕的是,从未注意到它们?)。
X.509 是一个非常复杂的算法、技术、规范和委员会的集合,很难做到正确。尝试使用 C 等不受保护的编程语言“手动”解码 X.509 证书是获取缓冲区溢出的一种简单方法。
Daniel Bleichenbacher在 1998 年发现了一个很好的针对 RSA 的攻击。当您使用 RSA 加密一条数据时(就像ClientKeyExchange
SSL 中的消息一样),必须填充要加密的数据,以便生成与 RSA 模数长度相同的字节序列。填充主要由随机字节组成,但有一点结构(值得注意的是,填充后的前两个字节必须是 0x00 0x02)。
解密后(然后在服务器上),必须找到并删除填充。碰巧的是,当时服务器解密但获得了无效的填充(0x00 0x02 字节不存在),然后它用警报消息报告它(根据 SSL 规范),而有效的填充导致服务器使用看似解密的值并继续握手。
这种东西被称为填充预言机。它允许攻击者发送任意字节序列,就好像它是加密的预主密钥一样,并知道该序列的解密是否会产生有效的填充。这只是一个 1 位的信息,但足以通过数百万个请求(使用巧妙制作的“加密”字符串)恢复私钥。
解决方法:当解密导致无效填充时,服务器继续使用随机的预主密钥。握手将在稍后失败,并带有Finished
消息。SSL 的所有当前实现都是这样做的。
发现填充预言的另一个区域是记录本身。考虑 CBC 加密和 HMAC。要加密的数据首先经过 MAC 处理,然后对结果进行加密。使用 CBC 加密,要加密的数据的长度必须是块大小的倍数(3DES 为 8 字节,AES 为 16 字节)。所以应用了一些填充,有一些结构。
当时(该攻击由 Vaudenay 在 2002 年发现),当 SSL 实现处理接收到的记录时,它针对以下两种情况返回不同的警报消息:
这是一个填充预言机,可用于恢复一些加密数据。它需要一个积极的攻击者,但这并不难。Vaudenay 实现了它,并且它扩展到了修改后的 SSL 实现在两种情况下都返回相同警报消息的情况,但在第二种情况下需要更长的时间才能返回,因为重新计算 MAC 需要时间(一个很好的演示定时攻击)。
因为人们从未学习过,微软在 ASP.NET 中使用的 SSL 实现在2010 年(八年后!)仍然没有修补,当时 Rizzo 和 Duong 重新实现了 Vaudenay 攻击并构建了一个恢复 HTTP cookie 的演示。
请参阅此页面以获取一些指示。必须注意,如果 SSL 使用了encrypt-then-MAC,则可以避免此类问题(错误记录将在 MAC 级别被拒绝,甚至在考虑解密之前)。
BEAST 攻击又出自 Duong 和 Rizzo,而且,它也是旧攻击的翻版(来自 Philip Rogaway,2002 年)。要了解这个想法,请考虑CBC。在这种操作模式下,每个数据块首先与前一个块的加密结果进行异或;这就是加密的 XOR的结果。这样做是为了“随机化”块并避免在 ECB 模式下发现的泄漏。由于第一个块没有“前一个”块,所以必须有一个初始化向量(IV),它对第一个块起到前一个块的作用。
事实证明,如果攻击者可以控制部分要加密的数据,并且可以预测将要使用的 IV,那么他就可以将加密机变成另一个解密预言机,并用它来恢复其他加密的数据。数据(攻击者没有选择)。然而,在 SSLv3 和 TLS 1.0 中,攻击者可以预测一条记录的 IV:它是前一条记录的最后一个块!因此,攻击者必须能够在流中发送一些数据,以便“推送”目标数据,在实现构建并发送前一个记录的点(通常在累积了 16 kB 的数据时),但是没有开始建造下一个。
TLS 1.1+ 受到保护,因为在 TLS 1.1(和后续版本)中,使用了每个记录的随机 IV。对于 SSLv3 和 TLS 1.0,一种解决方法是发送长度为零的记录:即,有效负载长度为零的记录——但具有 MAC 和填充和加密,并且 MAC 是根据密钥和序列计算得出的数字,所以它起到了随机数生成器的作用。不幸的是,IE 6.0 阻塞了零长度记录。其他策略涉及 1/n-1 拆分(一个n字节记录作为两个记录发送,一个带有单个字节的有效负载,另一个带有剩余的n-1)。
另一种解决方法是在可能的情况下强制使用非 CBC 密码套件——如果客户端发送的密码套件列表中有一个基于 RC4 的密码套件,即使客户端更喜欢基于 CBC 的密码套件。这个工具可以告诉你给定的服务器是否显然是这样的。(注意:BEAST 是对客户端的攻击,但是,通过选择 RC4 密码套件,服务器可以保护粗心的客户端。)
请参阅此页面以获取一些指示。虽然 TLS 1.1 是从 2006 年开始的,但 BEAST 攻击可能会迫使浏览器供应商最终升级。
至于任何好莱坞特许经营权,Duong 和 Rizzo 在 2012 年出版了续集的续集。CRIME 利用了多年前被理论化的漏洞,但只是在他们最近发布的演示中才生动地展示出来。CRIME 在与 BEAST 攻击相同的设置中利用压缩(攻击者可以在 SSL 连接中发送自己的一些数据,其中还会发送有趣的目标数据,例如 cookie)。粗略地说,攻击者将目标字符串的潜在值放入其数据中,如果匹配,则压缩会使结果记录更短。请参阅此问题进行(预认知)分析。
通过完全不使用 TLS 级别的压缩来避免 CRIME,这是浏览器现在所做的。Internet Explorer 和 IIS 从一开始就没有实现 TLS 级别的压缩(这一次,草率挽救了局面);Firefox 和 Chrome 在今年夏天实施并停用了它(他们被 Duong 和 Rizzo 预先警告过,他们对他们的活动负有责任)。
CRIME 在我的SSL 解释开头附近显示了我写作的原因:
SSL 在很大程度上(但不是绝对)实现了这些目标。
事实上,加密会泄露加密数据的长度。对此没有已知的好的解决方案。仅长度就可以揭示很多事情。例如,当使用网络监视器观察 SSL 连接时,我们可以发现流中的“额外握手”(因为每条记录的第一个字节标识了记录中的数据类型,并且它没有加密);通过记录的长度,很容易看出客户是否提供了证书。
(编辑:此部分已于 2014-10-15 添加)
“Poodle”攻击利用基于 CBC 的密码套件的 SSL 3.0 特有的缺陷。它依赖于 SSL 3.0 的一个经常被忽视的特性:大多数填充字节都被忽略了。在 TLS 1.0 中,填充(在记录中添加的字节以使长度与 CBC 加密兼容,仅处理完整块)是完全指定的;所有字节都必须有一个特定的值,并且接收者会检查它。在 SSL 3.0 中,填充字节内容被忽略,这允许攻击者执行几乎未被注意到的更改。该更改仅影响非应用数据,但可以以类似于 BEAST 的方式用作解密预言机。
可以在此答案中阅读更多详细信息。
人类永远学不会。为 SSL 添加漂亮的扩展有很大的压力,原因有很多,一开始总是看起来不错,但可能会引发额外的问题。
例如,考虑SSL FalseStart。主要是关于客户端在发送消息后立即发送其应用程序数据Finished
(在完全握手中),而无需等待Finished
来自服务器的消息。这减少了延迟,这是好的和善意的。然而,它改变了安全状况:在Finished
从服务器接收到消息之前,后者只是被隐式认证(客户端还没有证据表明目标服务器确实参与其中;它只知道它发送的任何内容都是可读的仅由预期的服务器提供)。这可能会产生影响;例如,攻击者可以模仿服务器到那时并强制,例如,客户端使用基于 CBC 的密码套件或 TLS 压缩。因此,如果客户端实施 FalseStart,那么它会降低针对 BEAST 和 CRIME 的保护措施的有效性,否则服务器可能会强制实施。
(谷歌今年春天禁用了 FalseStart,显然是因为与某些服务器的兼容性问题。无论如何,“30% 延迟减少”看起来很奇怪,因为 FalseStart 只会对完全握手产生影响,而不是缩写握手,所以我不相信这些所谓的好处;至少没有那么大。)