【问题标题】:Net:HTTP SSL negotiation timeout on Ubuntu 14.04网络:Ubuntu 14.04 上的 HTTP SSL 协商超时
【发布时间】:2024-05-18 10:05:02
【问题描述】:

经过漫长的一天后,我终于找到了一个我认为是 SSL/TLS 密码协商问题的根源,该问题与不支持最新最好版本的服务器有关。

堆栈:

  • Ubuntu 14.04 全面修补
  • OpenSSL 1.0.1f 2014 年 1 月 6 日
  • irb 0.9.6(09/06/30)
  • ruby 2.2.2p95(2015-04-13 修订版 50295)[x86_64-linux](使用 rbenv)

60 秒后,下面的 sn-p 给我一个错误:

require 'net/http'
require 'openssl'
uri = URI.parse('https://some_old_server/my/path')
http = Net::HTTP.new('some_old_server', 443)
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
http.use_ssl = true
response = http.request(Net::HTTP::Get.new(uri.request_uri))

Errno::ECONNRESET: Connection reset by peer - SSL_connect

如果我将它添加到代码中,它会起作用:

(...)
http.ciphers = ['AES128-SHA']
(...)

 => #<Net::HTTPOK 200 OK readbody=true>

这不是特定于 ruby​​ 的问题,但理想情况下存在 ruby​​ 解决方案。我无法将密码锁定为“AES128-SHA”,因为相同的代码可以处理许多可能支持也可能不支持此密码的网站。

有没有人遇到过这种情况并找到通用解决方案?

编辑:这似乎是由“TLS hang bug”引起的,并且是fixed in openssl 1.0.1g

新问题:是否有可以在 ruby​​ 端实现的解决方法?

更多信息。

运行 OpenSSL 1.0.1j 2014 年 10 月 15 日的 Gentoo 服务器没有这个问题。我尝试在 Ubuntu 14.04 服务器上安装 1.0.1j,重新编译 ruby​​(rbenv install 2.2.2),错误仍然存​​在。

我尝试过monkey patch ext/openssl,但没有成功。

使用上面链接中的整个密码列表不起作用。但是,使用一个小子集确实有效:

require 'net/http'
require 'openssl'
uri = URI.parse('https://some_old_server/my/path')
http = Net::HTTP.new('some_old_server', 443)
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
http.use_ssl = true
http.ciphers = %w{
          AES128-GCM-SHA256
          AES256-GCM-SHA384
          AES128-SHA256
          AES256-SHA256
          AES128-SHA
          AES256-SHA
          ECDHE-ECDSA-RC4-SHA
          ECDHE-RSA-RC4-SHA
          RC4-SHA
        }.join(":")
response = http.request(Net::HTTP::Get.new(uri.request_uri))

Openssl 与 ruby​​ 一致(应该如此)。在同一个系统上运行这些,复制了我在 ruby​​ 中看到的问题:

openssl s_client -connect some_old_server:443
CONNECTED(00000003)
(...)
  write:errno=104
  ---
  no peer certificate available
  ---
  No client certificate CA names sent
  ---
  SSL handshake has read 0 bytes and written 295 bytes
  ---
  New, (NONE), Cipher is (NONE)
  Secure Renegotiation IS NOT supported
  Compression: NONE
  Expansion: NONE
  ---

传递密码:

openssl s_client -cipher AES128-SHA -connect some_old_server:443
CONNECTED(00000003)
(...)
  ---
  No client certificate CA names sent
  ---
  SSL handshake has read 2721 bytes and written 425 bytes
  ---
  New, TLSv1/SSLv3, Cipher is AES128-SHA
  Server public key is 2048 bit
  Secure Renegotiation IS NOT supported
  Compression: NONE
  Expansion: NONE
  SSL-Session:
      Protocol  : TLSv1
      Cipher    : AES128-SHA
      Session-ID: removed
      Session-ID-ctx:
      Master-Key: removed
      Key-Arg   : None
      PSK identity: None
      PSK identity hint: None
      SRP username: None
      Start Time: 1454394952
      Timeout   : 300 (sec)
      Verify return code: 20 (unable to get local issuer certificate)
  ---

我在某个地方读到了使用

http.ssl_options = OpenSSL::SSL::OP_ALL

但 ssl_options 在 ruby​​ 2.2.2 上的 Net::HTTP 中不可用。

【问题讨论】:

标签: ruby openssl ubuntu-14.04 net-http


【解决方案1】:

在花费了比我愿意承认的更多的时间之后,我的解决方案是从 Ubuntu 14.04 升级到带有 OpenSSL 1.0.2d 9 Jul 2015 的 15.10。

虽然使用 openssl CLI 的 TLS 协商仍然挂起,但在 Ruby 中它不会:

require 'net/http'
require 'openssl'
require 'pp'

uri = URI.parse('https://broken_server/my/path')
http = Net::HTTP.new('broken_server', 443)

http.instance_eval {
  @ssl_context = OpenSSL::SSL::SSLContext.new
  @ssl_context.set_params({:options=>OpenSSL::SSL::OP_ALL})
}

http.verify_mode = OpenSSL::SSL::VERIFY_NONE
http.use_ssl = true
pp response = http.request(Net::HTTP::Get.new(uri.request_uri))

SSL context code above courtesy of @vinhboy.

上面的 CLI 等效项是 turned-on with the -bugs option:

openssl s_client -bugs -connect broken_server:443

【讨论】:

    最近更新 更多