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

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

对于那些不知道 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 中通过链接前端和后端来实现:

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 是一个聪明的实现。据我所知,它查询客户端的功能,然后只提供最好的功能,以消除任何疑虑。

相关内容