如何为新连接找到 NEGOTIATED 密码套件

How to find the NEGOTIATED cipher suite for a new connection

为了进一步提高基于 Jetty 9.3/JRE8 build 45 的嵌入式 Web 服务器应用程序的安全性,我想将我的服务器限制为仅服务 TLS 1.2(或未来的 1.2 和 1.3)以及这些密码套件:

0xC0,0x2B TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 Y [RFC5289]

0xC0,0x2C TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 Y [RFC5289]

但是,为了允许已协商 fall-back 密码套件的用户代理最终出现在我服务器的 handle() 函数中,Jetty 将线程交给我,我需要允许要传递一些其他密码套件,否则我无法发回一个简单的 HTML 页面,要求用户获得合适的浏览器。

所有这些都与 sslContextFactory set-up object 相得益彰,并且在我使用支持 TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 和 TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 的密码套件测试概念时工作正常.

我不确定为什么上面我最喜欢的两个还不起作用。一定是 ECDSA 问题,因为根据这个网站,我的 Goolge Chrome 也有 TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 作为首选套件:cc.dcsec.uni-hannover.de

但是,一旦在我的 handle() 方法中,我需要能够查明是否选择了上述密码套装之一,以便在没有选择的情况下我可以通知用户他需要浏览器像 FireFox 一样单独支持 TLS 1.2 和 Elliptic Curve,或者根据需要结合启用 OS Chrome(例如,Vista 的 Windows)等

我检查了 HTTP/1.1 RFC 并希望 'Connection' 或 'Upgrade' HTTP 标记包含一些有用的东西。我还搜索了可以包含协商密码套件的其他 HTTP header 名称。

然后我研究了一些相关的 RFC 以通过 TLS 进行 HTTP,希望可能有一种方法可以要求一些 header 重写以包含带有密码套件的标记。我还查看了 servlet 请求 object 上是否有某种方法会公开密码套件,但最接近的是更通用的 isSecure() 或 getScheme() (http/https)。我还枚举了所有 header 名称和相关值,以查看是否有内容。

最后我从 Microsoft 找到了一个 link 解释如何从 TLS record 中提取该信息,但后来我意识到当 Jetty 调用我的 handle() 方法时信息不再可用。

我知道 TCP/IP 和 TLS 1.2 是在 Jetty 获得连接之前处理的。因此密码套件可能不可用,就像无法从 handle() 方法内部提前(没有 connect/disconnect)阻止 TCP/IP 接受一样。

但也许有人知道获取密码套件的方法,或者可以说这是不可能的来结束我的搜索。

这里的一般理念是,我将仅使用上述密码套件和 HSTS 服务 HTTPS TLS 1.2/HTTP 2.0 + 将所有 HTTP 重定向到 HTTPS,但我总是需要允许其他不需要的连接到达我的句柄( ) 方法发送回基本 HTML 页面以请求浏览器升级。因此,在我的 handle() 中,我需要找出我在每个连接基础上处理的连接。密码套件是我最后的安宁。

因此,如果我只通过 setIncludeCipherSuits() 接受上述两个密码套件来关闭门,那么是否可以有一种方法来设置将发送回用户代理的消息(HTML)的 sslContextFactory。然后,用户将看到该消息,而不是浏览器显示的默认错误,该错误是由于缺乏通用密码套件支持而基于失败的密码套件协商。

非常感谢。

假设您将 ServerConnector 与启用了 SecureRequestCustomizerHttpConfiguration 一起使用,那么您可以这样做...

String cipherSuite = request.getAttribute("javax.servlet.request.cipher_suite");

这将 return SSLSession 在已建立的安全连接上使用的密码套件的名称。