修复正向保密

By -

对于 TLS(保障网络通信提供安全及数据完整性的一种安全协议),可能最大的抱怨是, TLS 握手动作缓慢,传输加密会造成很多 CPU 开销。当然,如果配置正确这些都不是问题。
最重要的通过 TLS 提高访客访问你网站的用户体验的一个特征是会话恢复。会话恢复是指当再一次连接到那些主机时,通过存储和重用以前的秘密信息。这大大减少了网络延迟和 CPU 的使用量。
我们可以在网络服务器和代理中启用会话恢复,但是很容易违背正向保密。为了找出为什么有实际标准的 TLS 库(即 OpenSSL )会是一件坏事和如何避免搞砸 PFS ,让我们仔细看看正向保密性和安装启用会话恢复功能的服务器端当前状态。

什么是(完美)正向保密?

(完美)的正向保密性是现代 TLS 设置的一个重要组成部分。它的核心是使用临时(短期)密钥来交换密钥,所以获得服务器连接的攻击者将不能使用任何的钥匙找到并破译过去可能被他们记录的 TLS 会话。

如果我们想要实现完全正向加密( PFS )的密钥交换,那么我们绝对不能让服务器的证书中含有公钥的RSA密钥对。因为这个密钥是长期存活的,很有可能比证书的有效日期还长。这意味着你有可能会在证书到期后仍然使用相同的密钥生成新的证书。如果服务器被攻破,那就太容易确定在磁盘或内存中的私钥的位置并用它来破译以前的 TLS 会话记录了。

使用更廉价产生密钥的Diffie-Hellman 交换密钥法,也就是我们可以使用一个密钥对,使用一次之后马上丢弃它。这样,虽然访问服务器的攻击者仍然可以攻破上面所说的认证部分并且可以拿到证书的私钥,但过去的 TLS 会却得到了保护。

如何恢复完美正向保密( PFS )会话?

TLS 提供两个会话恢复功能:会话 ID 和会话标签。为了更好地理解那些程序是为什么可以被攻击的,花点时间仔细研究细节是值得的。

会话 IDs

在一个完整的握手协议过程中,服务器发送一个会话标识 ID 作为“你好”消息的一部分。在随后的连接上,在保持连接的状态下,客户端可以使用该会话标识 ID ,并将其传递给服务器。由于服务器和客户端在会话 ID 的协助下都保存了上一次会话的“机密信息”,它们可以简单地恢复 TLS 会话到之前中断的地方。
为了能支持通过会话标识 ID 恢复会话,服务器必须维护一个映射之前会话标识 ID 到会话机密状态的缓存列表。这块缓存本身是主要的弱点,窃取缓存内容就可以破译其中所有会话标识 ID 对应的会话内容。
一个连接的前正向保密性是通过在服务器上保留会话信息的时间来限制实现的。理想情况下,您的服务器将使用一个平均大小的缓存,每天清除一次这块缓存。清除您的缓存可能不帮助,如果缓存本身生存在一个持久性存储周期,因为它可能是用来恢复被删除的数据的。如果它变成了一天一次,内存应该预备有足够能力抵抗这种攻击,确保旧数据重写正确。

会话标签

第二个恢复 TLS 会话的机制是会话标签。这个扩展将服务器的状态加密传送给客户端,用一个只有服务器知道的密钥进行加密。这个会话标签的密钥会一直保护 TLS 连接,它也将成为攻击者攻击的有力点。
客户将把从服务器发送的会话标签和一个 TLS 会话的加密信息一起存储。通过下一次 TLS 连接开始的时候再把会话标签发送回服务器,就可以实现它们以前会话的恢复。因为服务器仍然可以访问之前用以加密的密钥。
我们理想的情况是,让会话标签和会话标识 ID 有一样的保密限制。为了实现这一点,我们需要确保用于加密标签的密钥是每天变换的。它应该只作为会话缓存,不应该在持久存储中胜春,这样就不留任何可被追踪的痕迹。

Apache 配置

现在,我们来决定一下应该通过何种方式配置实现我们理想的会话恢复功能。让我们一起看一下在流行的 Web 服务器软件和负载均衡里是否依然支持,首先从 Apache 开始。
配置会话缓存
Apache 网络服务器提供了配置缓存的 SSLSessionCache 的指令,这块缓存包含了所有已经发生的 TLS 会话标识 ID 和其状态。你可以使用 shmcb 作为存储类型,这是一块共享内存分区的高性能周期缓冲区。它在所有的线程或进程中是可以被共享的,而且无论哪个线程或进程掌握用户的请求都可以恢复会话。

上面的例子通过路径 /path/to/ssl_gcache_data  建立一个大小为 512 Kib 的内存缓存区。取决于每天的访客量,缓存占用空间可能会很小(即有一个高的周转率)或很大(即有一个低的周转率)。
理想情况下,我们希望有一个缓存,每天更新,并没有好的办法可以确定正确的会话缓存大小。我们真正需要的是一种机制,这种机制负责告诉 Apache 在缓存中的一条记录被重写之前被允许的最长生存时间。无论循环缓冲区实际上是否已经循环过,这种机制都需要被执行。它还必须是一种周期性后台工作,确保即使没有在任何请求的情况下缓存也会被清除。

你可能想知道 SSLSessionCacheTimeout 指令是否可以在这种情况中有帮助,不幸的是没有。这种超时只检查会话 ID 在 TLS 连接开始的情况。它并不能从 session 缓存中清除条目记录。

配置会话标签
而Apache提供的 SSLSessionTicketKeyFile 指令指定密钥文件应该包含48字节,建议不要指定单个。Apache会对启动和使用加密会话标签会简单地生成一个随机的密钥,只要会话在运行。
关于这一点的好处是,会话密钥不会持久存储,坏处是它永远不会被更换。也就是说当Apache启动的时候一次生成,除非当Apache重新启动才被丢弃。对于大多数的服务器而言,这意味着他们在数月或几年的时间里使用相同的密钥。为了实现正向保密特性,我们需要每天动态更换会话标签密钥。但当前的Apache版本没有提供这样的方法。唯一的办法是使用固定时间作业来优雅地重启Apache,以确保每天产生一个新的关键。这听起来不像一个真正的解决方案而且并没有保证完全覆盖旧密钥。
在Apache正在运行的时候修改关键文件,你仍然需要重启服务以产生新的密钥。而且不要忘记,如果你使用一个密钥文件,应该把它存放在一个类似 tmpfs 的临时文件系统。

禁用会话标签
虽然禁用会话门票必定会带来负面的性能影响,但是为了正向加密需要,这正是你目前需要做的:

Ivan Ristic 补充说,如果想对 Apache 使用 SSLOpenSSLConfCmd  来禁用会话的标签功能,你必须运行尚未发布的 OpenSSL 1.0.2 。如果你想禁用装有早期 OpenSSL 版本 Apache 的会话标签功能, Ivan 有 Apache 2.2.x 的几个补丁和 Apache 2.4.x 的分支版本。
通过会话标签支持安全的会话恢复, Apache 应该为指定会话标签密钥最有效时间提供一个配置指令,至少在启动时自动生成。这将使我们能够每天简单地生成一个新的随机密钥,并覆盖旧的密钥。

Nginx的配置

另一种非常流行的 Web 服务器是 Nginx 。让我们把它在建立会话恢复方面和 Apache 比较一下。
配置会话缓存
Nginx 提供 ssl_session_cache 指令配置 TLS 会话缓存。缓存的类型应该被共享给多个 worker 之间共享:

上述行建立了一个 10MB 大小的内存缓存区。对于将会每天更新数据的 10MB 缓存,我们没有真正去考虑这个大小是否合适。和 Apache 类似, Nginx 应该提供一个配置指令允许缓存条目记录可以在某个时间被自动清除。任何一项没有被正确清洗的条目记录都可能会被拥有完全权限的服务器攻击者从存储器中读取。
你猜对了, ssl_session_timeout 指令只适用于当试图在连接开始时恢复会话。过时的条目在生存周期结束后将不会被自动删除。

配置会话标签
Nginx 可以使用 ssl_session_ticket_key 指令指定会话标签文件。而且下一次你可能通过不指定单个和在服务启动时产生随机密钥做的更好。会议标签密钥将永远不会被更换,并可能在数月或几年的时间里被用来加密会话标签。
Nginx 中一样也没有提供任何方法去自动更换密钥。使用周期作业方法加载配置日常可能有效,但并不是一个真正的解决办法。

禁用会话标签
为了给访客提供正向加密的会话服务,你最好的做法就是因此关闭会议标签功能支持,直到一个合适的解决方案出现。

HAProxy 配置

HAProxy ,流行的负载均衡器,和 Apache 和 Nginx 有着同样的问题。他们都是依赖于 OpenSSL ,TLS 实现的。
配置会话缓存
该会话缓存的大小可以用 tune.ssl.cachesize 指令设置,接受一些“块”。 HAProxy 的文档试图帮助和解释每个存储会话需要多少“块”。但我们又不能保证至少每天需要多少。我们需要一个指令自动清除条目,就像在 Apache 和 Nginx 里一样。
是的,这 tune.ssl.lifetime 指令不影响条目在缓存中的生存时间。
配置会话标签
HAProxy 不允许配置会话标签参数。它默认支持这个特性因为 OpenSSL 默认启用。因此, HAProxy 将总是在启动时产生会话标签密钥和使用它加密进程的整个生命周期。
每天正常重启 HAProxy 可能更新密钥的唯一途径。这是一个纯粹的假设,请在使用该产品之前做一下测试。
禁用会话标签
你可以使用 no-tls-tickets 指令禁用 HAProxy 里支持的会话标签功能:

这个软件以前的一个版本表示关闭会议标签功能是不可能的。感谢 HAProxy 团队纠正了自己的错误!

多服务器的会话恢复

如果你有多个 Web 服务器作为后端服务器,不幸的你就必须指定会话标签密钥文件和像个邪恶的黑客在午夜时重新加载服务配置。
虽然在多台使用 memcached (一个高性能的分布式内存对象缓存系统)的服务器中共享会话缓存是可能的,但使用会话标签的话你“只”共享一个或多个会话票证的钥匙,而不是整块缓存。客户端将会小心储存和丢弃你的会话标签。
推特上有一篇关于他们如何管理多个网络前端到后端的帖子,并对他们的每一台机器会话标签密钥都妥善分类。如果你有一个类似的设置和通过支持会话标签功能来提高响应速度,我建议阅读一下。
请记住,为了使正向加密与会话标签正确地实现统一,推特不得不写自己的网络服务器,这可能不是你想做的事情。
如果 OpenSSL 或所有流行的 Web 服务器和负载平衡器将开始致力于帮助在默认情况下实现正向加密,服务器管理员提供保密性就可以摆脱定制前后端的辛苦或黑客了,只需要更换密钥就行。

原文链接:https://timtaubert.de/blog/2014/11/the-sad-state-of-server-side-tls-session-resumption-implementations/

译文链接:http://www.linuxstory.org/tls-session-resumption

有个文学梦的程序员。努力学习代码中!Fighting···

2 Comments to 修复正向保密

发表评论

电子邮件地址不会被公开。

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据