HTTPS证书交换如何工作(例如在suche.org上)?


20

对于那些不知道Search.org是什么的网站,它是一个在每个类别上均对SSL Labs拥有完美A +评级的网站:(Search.org SSL Labs结果)。当我打开另一张有关无法在Chrome中使用的ECC证书的票证时,我意识到了该网站,其中一名响应者以该网站为例。

令我感到困惑的是,尽管该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连接,同时也支持较旧的客户端?


我们是否应该使标题更通用,例如“ HTTPS证书切换逻辑”?
gf_

1
@gf_好主意。做完了
斯科特·克鲁克斯

Answers:


17

我非常确定他们正在检查客户端功能并采取相应的措施,如@Jeff答案中链接的线程中所述

要了解它的详细外观请看一下。它显示了HAProxy根据不同客户的能力为不同客户提供不同证书的一种实现。我已经进行了完整的复制/粘贴,以防止链接腐烂,并且因为我认为这个问题将来可能会引起关注:

SHA-1证书即将到期,您应该尽快升级到SHA-256证书...除非您的客户非常老,并且必须保持SHA-1兼容性一段时间。

如果您处于这种情况,则需要强制客户端升级(困难)或实施某种形式的证书选择逻辑:我们将其称为“证书交换”。

最具确定性的选择方法是向呈现TLS1.2 CLIENT HELLO的客户端提供SHA-256证书,该客户端在signature_algorithms扩展名中明确宣布支持SHA256-RSA(0x0401)。

签名算法扩展

现代网络浏览器将发送此扩展程序。但是,我不知道任何开源负载均衡器当前能够检查signature_algorithms扩展的内容。将来可能会出现这种情况,但是就目前而言,实现证书切换的最简单方法是使用HAProxy SNI ACL:如果客户端提供了SNI扩展,请将其定向到提供SHA-256证书的后端。如果未提供扩展名,则假定它是使用SSLv3或TLS某些损坏版本的旧客户端,并提供SHA-1证书。

这可以在HAProxy中通过链接前端和后端来实现:

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)进行改进,但是对于基本的证书交换配置,它可以完成工作!


9

https://community.qualys.com/thread/16387上提出了类似的问题

我认为这个答案是解决方案:

suche.org是一个聪明的实现。据我了解,它会查询客户端的功能,然后只提供最可用的功能,以消除任何疑问。


2
但是,“它查询客户端的功能”并不是完全有用的描述。几乎没有足够的信息供其他人进行自己的实现。
womble
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.