curl 和启用 sni 的服务器

curl 和启用 sni 的服务器

我正在使用以下命令对启用了 sni 的服务器运行 curl

curl --cacert CustomCA.crt -H "Host: example.com" https://1.2.3.4/foo

但是,我没有获得正确的证书,其中通用名称 (CN) 设置为 example.com(因此证书验证失败)。我知道 SNI 配置正确完成,因为我看到在通过 Web 浏览器访问时提供了正确的证书。以防万一,我当前的环境是

> curl --version
curl 7.35.0 (x86_64-pc-linux-gnu) libcurl/7.35.0 OpenSSL/1.0.1f zlib/1.2.8 libidn/1.28 librtmp/2.3
Protocols: dict file ftp ftps gopher http https imap imaps ldap ldaps pop3 pop3s rtmp rtsp smtp smtps telnet tftp 
Features: AsynchDNS GSS-Negotiate IDN IPv6 Largefile NTLM NTLM_WB SSL libz TLS-SRP 
> lsb_release -a
LSB Version:    core-2.0-amd64:core-2.0-noarch:core-3.0-amd64:core-3.0-noarch:core-3.1-amd64:core-3.1-noarch:core-3.2-amd64:core-3.2-noarch:core-4.0-amd64:core-4.0-noarch:core-4.1-amd64:core-4.1-noarch:security-4.0-amd64:security-4.0-noarch:security-4.1-amd64:security-4.1-noarch
Distributor ID: Ubuntu
Description:    Ubuntu 14.04.1 LTS
Release:        14.04
Codename:       trusty

编辑:我忘了说,没有 DNS 条目将 example.com 映射到 1.2.3.4。这实际上是我工作的一部分,我用 ruby​​ 做了如下操作:

  context = OpenSSL::SSL::SSLContext.new
  context.ca_file = 'CustomCA.crt'
  context.verify_mode = OpenSSL::SSL::VERIFY_PEER

  tcp_client = TCPSocket.new('1.2.3.4', 443)
  ssl_client = OpenSSL::SSL::SSLSocket.new(tcp_client, context)
  ssl_client.hostname = 'example.com'
  ssl_client.connect
  cert = OpenSSL::X509::Certificate.new(ssl_client.peer_cert)
  cert_ca = OpenSSL::X509::Certificate.new(File.read(ca_path))
  ssl_client.sysclose
  tcp_client.close

我只是想知道如何仅使用 curl 来重新创建类似的东西。

并且...通过编辑我自己的 /etc/hosts 副本,该命令将正常工作

1.2.3.4 example.com

这是为什么?

编辑 2:通过 openssl 进行

openssl s_client -connect 1.2.3.4:443 -servername example.com

答案1

主机标头与 SNI 无关。要使用 SNI,您必须在 URL 中使用主机名,即使用https://example.com/而不是http://1.2.3.4/(当然使用 https:// 而不是 http://)。

更多详细信息:SNI 在 TLS 握手(ClientHello)中发送主机名。然后,服务器根据此信息选择正确的证书。只有在成功建立 TLS 连接后,它才会发送包含您指定的 Host 标头的 HTTP 请求。

关于您的编辑/评论:

  • 我想知道,如果没有主机的 DNS 条目,您如何通过浏览器成功访问该网站。如果浏览器不知道主机名,它也无法使用 SNI。
  • 如果您添加主机/IP 映射,/etc/hosts它将在https://example.com使用 curl 访问时起作用,因为您知道您拥有 SNI 的主机名和 TCP 连接的匹配 IP。
  • 您的 ruby​​ 代码设置了 ssl_client.hostname。这与您使用 curl 设置的 HTTP 主机标头不同。
  • 我没有看到 curl 的选项,您可以在其中独立设置 TLS SNI 的主机名和 TCP 连接的 IP。

答案2

参考后终于找到了答案

curl --cacert CustomCA.crt --resolve example.com:443:1.2.3.4 https://example.com/foo

相关内容