curl:如何为https请求指定目标主机名

时间:2018-05-10 18:25:57

标签: ssl curl sni

我有一个x.example,为a.exampleb.example提供流量。 x.example拥有a.exampleb.example的证书。 a.exampleb.example的DNS尚未设置。

如果我为/etc/hosts添加a.example条目,指向x.example的IP并运行curl -XGET https://a.example,则会获得200.

但是如果我运行curl --header 'Host: a.example' https://x.example,我会得到:

  

卷曲:(51)SSL:没有替代证书主题名称与目标匹配   主机名x.example

我认为它会使用a.example作为主机。也许我不理解SNI / TLS是如何工作的。

因为a.example是一个HTTP标头,TLS握手还没有访问权限吗?但它本身可以访问URL吗?

2 个答案:

答案 0 :(得分:6)

事实上,TLS中的SNI并不像那样。 SNI,因为与TLS相关的所有内容都发生在任何类型的HTTP流量之前,因此在该步骤中不会考虑Host标头(但稍后将对网络服务器有用,以便知道您正在连接哪个主机) )。

因此,要启用SNI,您需要HTTP客户端中的特定交换机,以告知它在握手期间使用您需要的主机名值发送相应的TLS扩展。

如果是curl,您至少需要版本7.18.1(基于https://curl.haxx.se/changes.html),然后它似乎会自动使用Host标头中提供的值。它还取决于它链接到哪个OpenSSL(或您平台上的等效库)。

参见https://curl.haxx.se/docs/knownbugs.html的第1.10点,其中提到了一个错误,但解释了会发生什么:

  

当给出一个带有主机名部分尾随点的URL:“https://example.com./”时,libcurl将剥离该点,并在内部使用不带点的名称,并在HTTP Host:header中将其发送为无点并在TLS SNI字段中。

--connect-to选项对您的情况也很有用。或--resolve代替/etc/hosts,例如https://curl.haxx.se/mail/archive-2015-01/0042.htmlhttps://makandracards.com/makandra/1613-make-an-http-request-to-a-machine-but-fake-the-hostname 您可以在所有情况下添加--verbose,以查看更多详细信息。请参阅此示例:https://www.claudiokuenzler.com/blog/693/curious-case-of-curl-ssl-tls-sni-http-host-header;您还将看到如何使用openssl直接测试。

如果a.example中有/etc/hosts,则应该使用https://a.example/运行curl,它应该处理Host标头,因此SNI(或使用{{ 1}}代替)

答案 1 :(得分:0)

选择的答案可以帮助我找到答案,即使它没有包含。 Patrick Mevzek提供的邮件/归档链接中的答案具有错误端口号。因此,即使遵循该答案也将导致其继续失败。

我使用this container运行调试服务器来检查请求。我强烈建议调试此类问题的任何人都这样做。

这是如何解决OP的问题。

# Instead of this:
# curl --header 'Host: a.example'        https://x.example

# Do:
  ip=$(dig +short x.example | head -n1)
  curl -sv   --resolve a.example:443:$ip https://a.example

注意:由于您使用的是https,因此必须在443参数中使用--resolve,而不要像{{3} }