这篇文章是《https优化必须了解ChaCha20-Poly1305算法》的延伸。现在我们知道在HTTPS协议中,主流的加密算法是AES-GCM和ChaCha20-Poly1305算法,那么服务器应该优先使用那个算法呢?或者说密码套件协商的规则是什么?
密码套件协商规则
假设台式机客户端(比如浏览器)在进行HTTPS握手的时候,会发送一组本机支持的密码套件(排在第一位的加密算法是AES-GCM,第二位的是ChaCha20-Poly1305);假设移动设备的客户端在进行HTTPS握手的时候,会发送一组本机支持的密码套件(排在第一位的加密算法是ChaCha20-Poly1305,第二位的是AES-GCM),那么服务器和客户端应该协商出那个密码算法呢?
在TLS密码库中(OpenSSL、NSS),协商一致的密码套件实际上是由服务器决定的,比如在Nginx中配置:
#配置(1)
ssl_ciphers 'ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256';
ssl_prefer_server_ciphers on;
其中 ssl_prefer_server_ciphers 指令解释如下:
Specifies that server ciphers should be preferred over client ciphers
也就是说最终协商出的密码套件以服务器配置为准。
如果客户端发送的密码套件同时包含ChaCha20-Poly1305和AES-GCM,而服务器也同时支持这两种算法,那最终选择的密码套件取决于服务器的配置。在上面的配置中,ECDHE-ECDSA-CHACHA20-POLY1305优先级更高,也就是最终会使用ChaCha20-Poly1305算法。
如果 ssl_ciphers 指令对应的算法调换下顺序,比如:
# 配置(2)
ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-ECDSA-CHACHA20-POLY1305';
ssl_prefer_server_ciphers on;
那么最终会使用 AES-GCM 算法。
聪明的同学可能会猜到,以上面的配置(1)为例,ECDHE-ECDSA-AES128-GCM-SHA256很有可能永远不会被选择(除非某个客户端不支持 ChaCha20-Poly1305 算法),确实是这样的。
那么为什么密码套件协商要以服务器为准呢?
- 从安全性考虑,因为如果以客户端密码套件优先级配置为主,那么攻击者可以强迫服务器最终协商出相对不安全的密码套件。
- 服务器可控性更高,比如说大部分服务器是 intel 芯片,你觉得它愿意使用 ChaCha20-Poly1305 算法吗?
等价加密算法组
等价加密算法组直白的说,就是服务器智能的选择密码套件(以客户端支持的密码套件为主),我们先不考虑等价加密算法组是否有用,先看看它是什么概念。
等价加密算法组(Equal preference cipher groups)是 BoringSSL(从OpenSSL fork出的密码库)提出来的,如果你查看 Cloudflare 推荐的 TLS配置(https://github.com/cloudflare/sslconfig),会发现如下的配置:
ssl_ciphers '[ECDHE-ECDSA-AES128-GCM-SHA256|ECDHE-ECDSA-CHACHA20-POLY1305]:ECDHE+AES128';
ssl_prefer_server_ciphers on;
首先说明的是,如果你在nginx中这样配置,启动nginx的时候会报错的,因为nginx使用的OpenSSL不支持等价加密算法组。cloudFlare现在已经使用了 BoringSSL,所以默认就支持等价加密算法组。
等价加密算法组的配置指令很简单,使用“[]”符号将优先级顺序一样的密码套件配置在一起(多个密码套件用“|”符号分隔)。
一旦如此配置,如果客户端优先发送AES-GCM密码套件,那么最终协商出的密码套件就是AES-GCM;如果客户端优先发送ChaCha20-Poly1305密码套件,那么最终协商出的密码套件就是ChaCha20-Poly1305。
需要注意的是,在这个例子中,[ECDHE-ECDSA-AES128-GCM-SHA256|ECDHE-ECDSA-CHACHA20-POLY1305] 的配置优先级比 ECDHE+AES128 更高,这说明服务器优先级更高(ssl_prefer_server_ciphers on),这一点需要和等价加密算法组的配置区分。
OpenSSL 支持等价加密算法组
考虑到 OpenSSL 的普及性,那么如何让 OpenSSL 也支持这一特性呢?可以打一个patch。
如果你使用的是 OpenSSL 1.1,那么可以进行下列的配置(仅仅描述openssl打patch):
$ wget "https://gitlab.com/buik/openssl/-/archive/openssl-patch/openssl-openssl-patch.zip"
$ unzip openssl-openssl-patch.zip
$ tar xvf openssl-1.1.0f.tar.gz
$ cd openssl-1.1.0f
$ patch -p1 < ../openssl-1.1/OpenSSL1.1f-equal-preference-cipher-groups.patch
如果使用的是 OpenSSL 1.1.1,目前还没有patch支持。
等价加密算法组真的有用?
大家可以思考下,为什么OpenSSL 1.1.1的最新版本还没有支持这特性呢?原因可能有多方面,看上去很不错的一个概念,还能让移动设备使用性能更高的ChaCha20-Poly1305算法,何乐而不为呢?
但实际上目前ChaCha20-Poly1305算法的优势没有想象的大。
1:从客户端考虑
移动设备很多使用 ARM 架构,在 《https优化必须了解ChaCha20-Poly1305算法》 也提到,ChaCha20-Poly1305 算法性能是 AES-GCM 的3倍。
可现在移动设备大部分采用 ARM V8 架构,本身已经支持 AES-NI 加速了(比如 iPhone5s以后手机,或者现在的小米手机,我实际测试了下,优先发送的密码套件是AES-GCM)。
就光这一点,直接可以宣告 ChaCha20-Poly1305 算法可能不会普及,从客户端的角度看,不管是台式机还是移动设备,AES-GCM 足够快了。
2:从服务器考虑
大部分台式机和服务器都使用 intel 架构,支持 AES-NI 指令,使用 AES-GCM 密码套件最合适,如果强制让它使用 ChaCha20-Poly1305 算法,性能反而不高(至少对服务器是这样的)。
我们总说 HTTPS 性能优化,需要仔细考虑是优先优化服务器端还是客户端,还是同时优化,这有个取舍。
总结
综合来说,大家也看到了,其实 ChaCha20-Poly1305 算法并没有那么流行,OpenSSL 目前不支持等价加密算法组也可理解了,不过在下个版本中,OpenSSL 还可能会支持,因为这确实一个很有趣的特性。
对于大部分公司来说,其实HTTPS的优化没有太多的银弹,我们只要老老实实的选择主流的配置即可,比如 Mozilla 建议的配置(https://mozilla.github.io/server-side-tls/ssl-config-generator/),没有必要太折腾;当然对于大型企业来说,尤其是 CDN 厂商来说,将性能优化做到极致是可理解的,当然他们更多的会考虑服务器端的 HTTPS 性能。
本文发表于【2018-12-07】,地址是https://mp.weixin.qq.com/s/ev8UDX6sZ7VCYKY7-XUBKA,欢迎大家关注,我的公众号(ID:yudadanwx,虞大胆的叽叽喳喳)
网友评论