【发布时间】:2011-09-29 11:48:08
【问题描述】:
我正在编写一个 HTTP 代理,但我无法理解通过 TLS 发出 CONNECT 请求的一些细节。为了更好地了解情况,我正在尝试使用 Apache 来观察它如何与客户端交互。这是来自我的默认虚拟主机。
NameVirtualHost *:443
<VirtualHost>
ServerName example.com
DocumentRoot htdocs/example.com
ProxyRequests On
AllowConnect 22
SSLEngine on
SSLCertificateFile /root/ssl/example.com-startssl.pem
SSLCertificateKeyFile /root/ssl/example.com-startssl.key
SSLCertificateChainFile /root/ssl/sub.class1.server.ca.pem
SSLStrictSNIVHostCheck off
</VirtualHost>
Apache 和我的客户之间的对话是这样的。
一个。客户端连接到example.com:443 并在 TLS 握手中发送example.com。
b.客户端发送 HTTP 请求。
CONNECT 192.168.1.1:22 HTTP/1.1
Host: example.com
Proxy-Connection: Keep-Alive
c。阿帕奇说HTTP/1.1 400 Bad Request。 Apache 错误日志说
Hostname example.com provided via SNI and hostname 192.168.1.1
provided via HTTP are different.
似乎 Apache 不查看 Host 标头,只是查看它的存在,因为 HTTP/1.1 需要它。如果客户端发送Host: foo,我会得到相同的失败行为。如果我在没有 TLS 的情况下向 example.com:80 发出 HTTP 请求,那么 Apache 会将我连接到 192.168.1.1:22。
我不完全理解这种行为。 CONNECT 请求有问题吗?我似乎找不到解释这一切的 RFC 的相关部分。
【问题讨论】:
-
上面的 SNI 表示握手中发送的主机名,而不是主机头。正如我在下面的回答中所写,混合 SSL 和 CONNECT 代理并不典型。看起来 Apache 在进行证书验证时根本没有预料到这一点。您可以在 Apache 中尝试
SSLStrictSNIVHostCheck off。