Ruby SSL错误 - sslv3警告意外消息

时间:2011-07-25 19:09:34

标签: ruby openssl mechanize

我正在尝试使用ruby脚本连接到服务器https://www.xpiron.com/schedule。但是,当我尝试连接时:

require 'open-uri'
doc = open('https://www.xpiron.com/schedule')

我收到以下错误消息:

OpenSSL::SSL::SSLError: SSL_connect returned=1 errno=0 state=SSLv2/v3 read server hello A:  sslv3 alert unexpected message         
    from /usr/local/lib/ruby/1.9.1/net/http.rb:678:in `connect'
    from /usr/local/lib/ruby/1.9.1/net/http.rb:678:in `block in connect'
    from /usr/local/lib/ruby/1.9.1/timeout.rb:44:in `timeout'
    from /usr/local/lib/ruby/1.9.1/timeout.rb:87:in `timeout'
    from /usr/local/lib/ruby/1.9.1/net/http.rb:678:in `connect'
    from /usr/local/lib/ruby/1.9.1/net/http.rb:637:in `do_start'
    from /usr/local/lib/ruby/1.9.1/net/http.rb:626:in `start'
    from /usr/local/lib/ruby/1.9.1/net/http.rb:1168:in `request'
    from /usr/local/lib/ruby/1.9.1/net/http.rb:888:in `get'
    from (irb):32
    from /usr/local/bin/irb:12:in `<main>'

我正在运行Ruby 1.9.2p180。它似乎适用于其他一些机器,因此它可能是OpenSSL或Ruby的配置问题。我尝试重新安装所有SSL库,并从头开始重建Ruby,但似乎没有任何工作。有人遇到过这个问题吗?

更新

在非工作机器上,openssl版本为0.9.8o 01 Jun 2010

在工作机器上,它是0.9.8k 25 Mar 2009

所以最近的一个似乎正在崩溃。

此外,如果我使用不同的HTTP客户端(Patron,基于libcurl),它可以工作:

require 'patron'

sess = Patron::Session.new
sess.timeout = 5
url = 'https://www.xpiron.com/schedule'
resp = sess.get(url)
puts "#{resp.body}"

所以这似乎是Ruby的OpenSSL绑定的一个问题。

5 个答案:

答案 0 :(得分:9)

回答我自己的问题。

问题似乎在于Ruby如何协商SSL连接。 Xpiron的TLS机制出现错误,它会抛出错误而不是重试其他SSL版本。

如果强制SSL版本为3.0,则可以:

require 'net/http'
url = URI.parse('https://www.xpiron.com/schedule')
req = Net::HTTP::Get.new(url.path)
sock = Net::HTTP.new(url.host, 443)
sock.use_ssl = true
sock.ssl_version="SSLv3"
sock.start do |http|
    response = http.request(req)
end

我还在Ruby的bug tracker上创建了一个问题。

答案 1 :(得分:2)

我认为这是因为https网址。有一个平均的,完全不安全的黑客绕过这个,但请谷歌为它自己承担风险。我宁愿使用Net :: HTTP:

向您展示这样做的安全方法
require 'net/http'

url = URI.parse('https://www.xpiron.com/schedule')
req = Net::HTTP::Get.new(url.path)
sock = Net::HTTP.new(url.host, 443)
sock.use_ssl = true
store = OpenSSL::X509::Store.new
store.add_cert OpenSSL::X509::Certificate.new(File.new('addtrust_ca.pem'))
store.add_cert OpenSSL::X509::Certificate.new(File.new('utn.pem'))
store.add_cert OpenSSL::X509::Certificate.new(File.new('user_first_ca.pem'))
store.add_cert OpenSSL::X509::Certificate.new(File.new('xpiron.pem'))
sock.cert_store = store
sock.start do |http|
  response = http.request(req)
end

您可以通过在浏览器中输入您的URL(例如Firefox),然后点击URL /更多信息/查看证书/详细信息 - >左侧的图标来获取证书文件。点击链中的每个证书,然后将其导出为我上面使用的名称下的PEM文件。将这些文件放在与引用它们的脚本相同的目录中。那应该是魔术。但我注意到登录该页面需要cookie,因此可能需要更多努力才能适当地修改您的请求。

答案 2 :(得分:1)

经过一整天的黑客攻击后,这个终于为我工作了:

url = URI.parse("https://full-url?test=1&foo=bar")
response = Net::HTTP.start(url.host, use_ssl: true, ssl_version: 'SSLv3', verify_mode: OpenSSL::SSL::VERIFY_NONE) do |http|
  http.get url.request_uri
end

答案 3 :(得分:0)

请注意,rest-client gem在编写本文时没有办法设置它。有an outstanding pull request但不幸的是,宝石似乎没有被维护。

答案 4 :(得分:0)

可以是

var url = 'http://192.168.59.103/members';
$http.get(url).then(
    function(response) {
        console.log('success',response)
    },
    function(data) {
        // Handle error here
    })