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

lf2*_*215 3 ssl curl sni

我有一个x.example服务于a.example和的流量b.examplex.example有两个证书a.exampleb.example。对于DNS a.exampleb.example尚未成立。

如果添加指向ip并运行的/etc/hosts条目,则会得到200。a.examplex.examplecurl -XGET https://a.example

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

curl:(51)SSL:没有其他证书使用者名称与目标主机名称x.example匹配

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

因为a.example是HTTP标头,所以TLS握手尚无法访问它?但是它确实可以访问URL本身吗?

Bru*_*sky 10

选定的答案帮助我找到了答案,即使它不包含答案。Patrick Mevzek 提供的邮件/存档链接中的答案有错误的端口号。因此,即使遵循该答案也会导致它继续失败。

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

以下是如何解决 OP 的问题。

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

# Do:
  host=a.example
  target=x.example

  ip=$(dig +short $target | head -n1)
  curl -sv   --resolve $host:443:$ip https://$host

Run Code Online (Sandbox Code Playgroud)

如果您想忽略错误的证书匹配,请使用-svk代替-sv

curl -svk --resolve $host:443:$ip https://$host
Run Code Online (Sandbox Code Playgroud)

注意:由于您使用的是 https,因此您必须443--resolve参数中使用,而不是80按照邮件/存档中的说明使用


Pat*_*zek 7

确实,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提供主机名部分带有尾随点的URL:“ https://example.com./ ”时,libcurl将剥离该点并在内部使用不带点的名称,并在HTTP主机中将其发送为不带点的:标头和“ TLS SNI”字段中。

--connect-to选项在您的情况下也可能有用。或--resolve替代/etc/hosts,例如,参见https://curl.haxx.se/mail/archive-2015-01/0042.htmlhttps://makandracards.com/makandra/1613-make-an-http -请求一台机器但伪造的主机名 您可以--verbose在所有情况下添加,以更详细地了解正在发生的事情。参见以下示例:https : //www.claudiokuenzler.com/blog/693/curious-case-of-curl-ssl-tls-sni-http-host-header;您还将在那里看到如何直接使用进行测试openssl

如果您有a.example,则应该使用/etc/hostscurl进行处理https://a.example/,并且应该注意Host标题和SNI(或改用SNI --resolve


小智 6

我有类似的需求。没有 sudo 访问权限来更新主机文件。

我使用解析参数,并添加 DNS 主机名作为标头参数。

--resolve <dns name>:<port>:<ip addr>

curl --request POST --resolve dns_name:443:a.b.c.d 'https://dns_name/x/y' --header 'Host: dns_name' ....
Run Code Online (Sandbox Code Playgroud)

干杯..