禁用 Ruby net/http 的 SNI 扩展 - 使用 SSL/TLS 的 IP 地址

Disable SNI Extension for Ruby net/http - Using IP address with SSL/TLS

我有一个 Ruby 轮询脚本 运行 在 IP 范围内的一组服务器上。我非常强烈更喜欢通过 IP 地址而不是主机名进行轮询,因为:

1) 我已经定义了要轮询的 IP 地址范围,并且主机名 arbitrary/change 很多

2) 因为它们变化很大,所以大多数主机名没有反向 DNS 查找,所以我无法根据 IP 设计主机名列表

在我们的 Web 服务器对此轮询没有问题之前,但是在不接受 SSLv3 通信的新服务器上,这是我 运行 我的轮询时遇到的错误:

/home/dashboard/.rvm/rubies/ruby-2.1.6/lib/ruby/2.1.0/net/http.rb:923:in `connect': SSL_connect returned=1 errno=0 state=unknown state: tlsv1 unrecognized name (OpenSSL::SSL::SSLError)

在服务器端,这是错误:

nss_engine_init.c(1802): start function ownSSLSNISocketConfig for SNI
nss_engine_init.c(1827): Search [val = 172.16.99.18] failed, unrecognized name

当我 运行 使用主机名进行投票时,一切正常。

这是 Ruby 中 HTTP 客户端代码的关键:

def init_http(url)
  uri = URI.parse(url)
  http = Net::HTTP.new(uri.host, uri.port)
  http.verify_mode = OpenSSL::SSL::VERIFY_PEER
  http.read_timeout = 10
  http.use_ssl = true
  #http.ssl_version = 'TLSv1'
  return [http, uri]
end

如您所知,我一直在研究 TLS 和 SSL 版本,因为我认为这可能是问题所在。我的下一个想法(Google 只有 Java 的证据)是,"How easy is it to just disable the SNI extension on my client?" 更一般的问题是,"Can I keep using IP addresses with Ruby net/http while taking advantage of newer, more secure communication protocols?"

... tlsv1 unrecognized name (OpenSSL::SSL::SSLError)

在大多数情况下,这不是您可以通过在客户端禁用 SNI 来解决的问题。当您在同一个 IP 地址上拥有多个证书并且如果您只是通过 IP 地址连接并且不发送请求的主机名(即禁用 SNI)时,SNI 是必需的,服务器将不知道它应该提供哪个证书 - 然后导致以上错误。

I very strongly prefer to do this polling by IP address, not by hostname, ...

如果您必须处理需要 SNI 的服务器,那么您必须使用 SNI,并且必须使用具有正确主机名的 SNI,该主机名不一定与您从反向查找中获得的名称相同。

解决此问题的最简单方法是添加@steffenullrich 为 bug 10613 提到的补丁。

我所做的只是查看差异,然后自己编辑文件,但是如果您熟悉 Linux 补丁工具,您可以使用它。

对于那些不确定 /net/http.rb 所在位置的人,它与您的其他 Ruby 来源位于同一位置。例如,我在这里:

/home/myuser/.rvm/rubies/ruby-2.1.6/lib/net/http.rb

修补文件后,将 HTTP 对象的 .disable_sni 属性 设置为 true,并且不需要 SNI,允许在混合 TLS 通信中使用 IP 地址。