![HTTPS 证书切换如何工作(如在suche.org上)?](https://linux22.com/image/686974/HTTPS%20%E8%AF%81%E4%B9%A6%E5%88%87%E6%8D%A2%E5%A6%82%E4%BD%95%E5%B7%A5%E4%BD%9C%EF%BC%88%E5%A6%82%E5%9C%A8suche.org%E4%B8%8A%EF%BC%89%EF%BC%9F.png)
对于那些不知道 Suche.org 是什么的人来说,它是一个在 SSL Labs 的每个类别中都拥有完美 A+ 评级的网站:(Suche.org SSL 实验室结果)。我在打开另一张关于ECC 证书在 Chrome 中不起作用,其中一位回应者就以该网站为例。
让我困惑的是,尽管Protocol Support
报告中说该网站仅有的使用 TLSv1.2...
TLS 1.2 Yes
TLS 1.1 No
TLS 1.0 No
SSL 3 No
SSL 2 No
显然事实并非如此,因为在该Handshake Simulation
部分下,它显示一些模拟的旧客户端正在使用 TLSv1.0 进行连接……
Android 4.0.4 EC 384 (SHA256) TLS 1.0 TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA ECDH secp521r1 FS
Android 4.1.1 EC 384 (SHA256) TLS 1.0 TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA ECDH secp521r1 FS
Android 4.2.2 EC 384 (SHA256) TLS 1.0 TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA ECDH secp521r1 FS
Android 4.3 EC 384 (SHA256) TLS 1.0 TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA ECDH secp521r1 FS
Android 4.4.2 EC 384 (SHA256) TLS 1.2 TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 ECDH secp521r1 FS
这有点令人沮丧,因为如果我像这样在测试网站上禁用 TLSv1.0……
# Apache example
SSLProtocol all -SSLv3 -SSLv2 -TLSv1
在我的测试网站上运行 SSL Labs 扫描后,对于一些较旧的客户端,出现了以下结果:
Android 4.0.4 Server closed connection
Android 4.1.1 Server closed connection
Android 4.2.2 Server closed connection
Android 4.3 Server closed connection
Android 4.4.2 EC 384 (SHA256) TLS 1.2 TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 ECDH secp256r1 FS
如何才能同时允许 TLSv1.2 连接,同时还支持旧客户端?
答案1
我很确定他们正在检查客户端功能并采取相应措施,正如链接的帖子中解释的那样在@Jeff 的回答中。
要详细了解它是什么样子,请看一下在这。它展示了一种实现,HAProxy
根据不同客户端的功能为其提供不同的证书。我进行了完整的复制/粘贴,以防止链接腐烂,因为我认为这个问题将来可能会引起人们的兴趣:
SHA-1 证书即将淘汰,您应该尽快升级到 SHA-256 证书……除非您有非常老的客户端并且必须在一段时间内保持 SHA-1 兼容性。
如果您处于这种情况,您需要强制您的客户端升级(困难)或实施某种形式的证书选择逻辑:我们称之为“证书切换”。
最确定的选择方法是向提供 TLS1.2 CLIENT HELLO 的客户端提供 SHA-256 证书,该客户端在 signature_algorithms 扩展中明确宣布其支持 SHA256-RSA (0x0401)。
现代 Web 浏览器将发送此扩展。但是,我不知道目前有任何开源负载均衡器能够检查 signature_algorithms 扩展的内容。它可能会在将来出现,但目前实现证书切换的最简单方法是使用 HAProxy SNI ACL:如果客户端提供 SNI 扩展,则将其定向到提供 SHA-256 证书的后端。如果它不提供扩展,则假设它是一个使用 SSLv3 或某些损坏版本的 TLS 的旧客户端,并向其提供 SHA-1 证书。
这可以在 HAProxy 中通过链接前端和后端来实现:
global
ssl-default-bind-ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128
-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-R
SA-AES256-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!3DES:!MD5:!PSK
frontend https-in
bind 0.0.0.0:443
mode tcp
tcp-request inspect-delay 5s
tcp-request content accept if { req_ssl_hello_type 1 }
use_backend jve_https if { req.ssl_sni -i jve.linuxwall.info }
# fallback to backward compatible sha1
default_backend jve_https_sha1
backend jve_https
mode tcp
server jve_https 127.0.0.1:1665
frontend jve_https
bind 127.0.0.1:1665 ssl no-sslv3 no-tlsv10 crt /etc/haproxy/certs/jve_sha256.pem tfo
mode http
option forwardfor
use_backend jve
backend jve_https_sha1
mode tcp
server jve_https 127.0.0.1:1667
frontend jve_https_sha1
bind 127.0.0.1:1667 ssl crt /etc/haproxy/certs/jve_sha1.pem tfo ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:ECDHE-RSA-DES-CBC3-SHA:ECDHE-ECDSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA
mode http
option forwardfor
use_backend jve
backend jve
rspadd Strict-Transport-Security:\ max-age=15768000
server jve 172.16.0.6:80 maxconn 128
上述配置在名为“https-in”的前端接收入站流量。该前端处于 TCP 模式,并检查来自客户端的 CLIENT HELLO 中是否有 SNI 扩展的值。如果该值存在且与我们的目标站点匹配,它会将连接发送到名为“jve_https”的后端,该后端会重定向到同样名为“jve_https”的前端,其中配置了 SHA256 证书并将其提供给客户端。
如果客户端无法提供带有 SNI 的 CLIENT HELLO,或者提供的 SNI 与我们的目标站点不匹配,则会将其重定向到“https_jve_sha1”后端,然后重定向到提供 SHA1 证书的相应前端。该前端还支持较旧的密码套件以适应较旧的客户端。
两个前端最终都会重定向到名为“jve”的单个后端,该后端将流量发送到目标 Web 服务器。
这是一个非常简单的配置,最终可以使用更好的 ACL 进行改进(HAproxy 定期添加新的 ACL),但对于基本的证书切换配置,它可以完成工作!
答案2
有人问过类似的问题https://community.qualys.com/thread/16387
我认为这答案是解决方案:
suche.org 是一个聪明的实现。据我所知,它查询客户端的功能,然后只提供最好的功能,以消除任何疑虑。