![使用 HTTP 代理时 TLS Client Hello 缺少 SNI 标头](https://linux22.com/image/772993/%E4%BD%BF%E7%94%A8%20HTTP%20%E4%BB%A3%E7%90%86%E6%97%B6%20TLS%20Client%20Hello%20%E7%BC%BA%E5%B0%91%20SNI%20%E6%A0%87%E5%A4%B4.png)
我正在调试一个基于 Java 的应用程序的问题,该应用程序通过 HTTPS 检索 JSON 负载(来自 NIST 的 CVE 列表)。当我直接连接到 NIST 时,我成功检索了数据。当我使用 HTTP 代理时,我收到 TLS“无法识别的名称”错误,提示服务器名称指示存在问题。
我无法访问 Java 应用程序的代码,并且几乎没有能力来干扰 JVM 设置。因此,我直接使用 openssl 进行了一些单独的测试,并且能够在一定程度上重现该问题。
当我对以下调用进行 tcpdump 时,我可以看到客户端 Hello 数据包中存在 server_name 扩展:
openssl s_client -connect services.nvd.nist.gov:443
但是,如果我通过 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条目:
我相信这是目标服务器返回错误的原因(尽管据我所知,在这种情况下它应该返回默认证书)。
现在我可以通过手动指定服务器名称来使用代理来完成这项工作:
openssl s_client -connect services.nvd.nist.gov:443 -proxy myproxy:3128 -servername nvd.nist.gov
我的理解是,代理只是传输 TLS 数据,不应该修改它,所以这表明 openssl 选择在使用代理时不发送服务器名称扩展信息。为什么会这样?
(显然,在 openssl 情况下,我可以只指定 servername 参数,但对于 Java 应用程序,我没有这种奢侈。我希望如果我能理解为什么 openssl 选择不通过代理发送 SNI 详细信息,它可能会解释为什么 Java 似乎也这样做。)