使用 HTTP 代理时 TLS Client Hello 缺少 SNI 标头

使用 HTTP 代理时 TLS Client Hello 缺少 SNI 标头

我正在调试一个基于 Java 的应用程序的问题,该应用程序通过 HTTPS 检索 JSON 负载(来自 NIST 的 CVE 列表)。当我直接连接到 NIST 时,我成功检索了数据。当我使用 HTTP 代理时,我收到 TLS“无法识别的名称”错误,提示服务器名称指示存在问题。

我无法访问 Java 应用程序的代码,并且几乎没有能力来干扰 JVM 设置。因此,我直接使用 openssl 进行了一些单独的测试,并且能够在一定程度上重现该问题。

当我对以下调用进行 tcpdump 时,我可以看到客户端 Hello 数据包中存在 server_name 扩展:

openssl s_client -connect services.nvd.nist.gov:443

Wireshark 显示服务器名称扩展

但是,如果我通过 Squid 代理发送此信息,并使用以下内容转储代理和目标服务器之间的数据包,则客户端 Hello 数据包中不存在 server_name 扩展:

openssl s_client -connect services.nvd.nist.gov:443 -proxy myproxy:3128

openssl 的响应是:

140012895368512:error:14094458:SSL routines:ssl3_read_bytes:tlsv1 unrecognized name:../ssl/record/rec_layer_s3.c:1543:SSL alert number 112
---
no peer certificate available
---

我们可以看到数据包中没有server_name条目:

WireShark 显示缺少扩展

我相信这是目标服务器返回错误的原因(尽管据我所知,在这种情况下它应该返回默认证书)。

现在我可以通过手动指定服务器名称来使用代理来完成这项工作:

openssl s_client -connect services.nvd.nist.gov:443 -proxy myproxy:3128 -servername nvd.nist.gov

我的理解是,代理只是传输 TLS 数据,不应该修改它,所以这表明 openssl 选择在使用代理时不发送服务器名称扩展信息。为什么会这样?

(显然,在 openssl 情况下,我可以只指定 servername 参数,但对于 Java 应用程序,我没有这种奢侈。我希望如果我能理解为什么 openssl 选择不通过代理发送 SNI 详细信息,它可能会解释为什么 Java 似乎也这样做。)

相关内容