【问题标题】:HTTP library for Ruby with HTTPS, SSL Client Certificate and Keep-Alive support?具有 HTTPS、SSL 客户端证书和 Keep-Alive 支持的 Ruby HTTP 库?
【发布时间】:2013-09-24 01:19:23
【问题描述】:

我正在尝试用 Ruby 编写一个 HTTPS 客户端。它将使用 HTTPS 连接到服务器,传递身份验证令牌(通过单独的登录过程获得)和 SSL 客户端证书。

我正在使用rest-client 执行以下操作:

client = RestClient::Resource.new(url,
                         :ssl_client_cert  =>  OpenSSL::X509::Certificate.new(File.read('./certificate/client-2048.pem')),
                         :ssl_client_key   =>  OpenSSL::PKey::RSA.new(File.read('./certificate/client-2048.key'), ''),
                         :verify_ssl       =>  OpenSSL::SSL::VERIFY_NONE)

# ...

headers = {
  'X-Application' => APP_KEY,
  'X-Authentication' => @session_token,
  'content-type' => 'application/json',
  'Accept' => 'application/json'
}

response = client.post(request, headers)

这可行,但我想做的是使用 keep-alive 来避免每次我想提出请求时都必须经历建立连接的整个过程。所涉及的延迟使我正在编写的监控应用程序的用处大大降低。

但是,我似乎找不到的是一个提供以下功能的 Ruby 库:

  • HTTPS 支持
  • SSL 客户端证书支持
  • 保持活动状态

有一个pull request 正在等待应该提供它的rest-client。 httpartypersistent_httparty 但如果它支持 SSL 客户端证书,则有 no documentation for it

我可以派生rest-client,合并现在已经有点腐烂的拉取请求,然后使用它。但我肯定在这里遗漏了一些东西......是否有一个现有的图书馆可以提供我正在寻找的东西?或者 httparty 的一些文档解释了 SSL 客户端证书与该库的使用?

任何帮助将不胜感激。

【问题讨论】:

  • OpenSSL::SSL::VERIFY_NONE 通常是个坏主意。如果工作流程包括最低限度的常规检查,那么您可能会发现它不起作用。

标签: ruby http https keep-alive


【解决方案1】:

Ruby 标准库的 Net::HTTP API 满足您列出的要求:HTTPS 支持、SSL 客户端证书支持和 Keep-Alive。

由于 Net::HTTP 可以在没有块语义的情况下实例化和重用,因此也很容易将其包装在您自己的库中。

#!/usr/bin/env ruby
#
# https://gist.github.com/sheldonh/4693e2eca35b62b22c55

require 'openssl'
require 'net/http'
require 'json'

class Gist

  DEFAULT_OPTIONS = {
    use_ssl: true,
    verify_mode: OpenSSL::SSL::VERIFY_PEER,
    keep_alive_timeout: 30,
    cert: OpenSSL::X509::Certificate.new(File.read('./client.cert.pem')),
    key: OpenSSL::PKey::RSA.new(File.read('./client.key.pem'))
  }


  def initialize(http = nil)
    if http
      @http = http
    else
      @http = Net::HTTP.start("api.github.com", 443, DEFAULT_OPTIONS)
    end
  end

  def fetch(id, file)
    response = @http.request Net::HTTP::Get.new "/gists/#{id}"
    JSON.parse(response.body)["files"][file]["content"]
  end

end


gist = Gist.new
puts gist.fetch "fc5b5c42ff2e22171f09", "gistfile1.txt"  # Lorem ipsum
puts gist.fetch "4693e2eca35b62b22c55", "gist.rb" # This script

【讨论】:

    【解决方案2】:

    有什么东西已经奏效了吗?

    我相信 HTTP 客户端库 Faraday 是近来更多 Ruby 社区行动的焦点。

    它带有一个:net_http_persistent adapter,它支持 SSL 客户端证书。您可能可以执行以下操作:

    ssl_options = {
      cert: OpenSSL::X509::Certificate.new(File.read('./certificate/client-2048.pem')),
      key:  OpenSSL::PKey::RSA.new(File.read('./certificate/client-2048.key'), 'mypassword')
    }
    conn = Faraday.new(url: 'https://example.com', ssl: ssl_options) do |faraday|
      faraday.adapter = Faraday::Adapter::NetHttpPersistent
    end
    
    conn.get '/my-resource'
    

    HTTP派对

    根据规格:

    ...方案为https时提供PEM证书时产生的连接

    • 使用提供的 PEM 证书
    • 将验证证书

    您可以使用pem classmethod 提供 PEM 格式的客户端证书。

    REST 客户端

    它并没有那么死——Larry Gilbert (@L2G) 仍在合并拉取请求并保持亮灯状态。他在问题跟踪器中点头表示普遍认可。我怀疑它目前不在他的优先级队列中。

    发送拉取请求的人@byroot 拥有been keeping his code up to date,因此您在等待时根本不需要做太多事情。

    【讨论】:

    • 我采用了 REST 客户端方法 - 比合并拉取请求更快、更容易。我分叉了包含它的 repo,并在我的 Gemfile 中安装了以下内容:gem 'rest-client', :github => 'duncan-bayne/rest-client', :branch => 'feature-keep-alive'。不过我会调查一个通往法拉第的港口,因为这似乎是未来的方向。
    • “我会调查”是指“两年后的 2015 年”。但是,嘿,迟到总比没有好...... :)
    【解决方案3】:

    你试过mechanize吗?

    根据examples,您可以像这样通过客户认证:

    require 'rubygems'
    require 'mechanize'
    
    # create Mechanize instance
    agent = Mechanize.new
    
    # set the path of the certificate file
    agent.cert = 'example.cer'
    
    # set the path of the private key file
    agent.key = 'example.key'
    
    # get the login form & fill it out with the username/password
    login_form = agent.get("http://example.com/login_page").form('Login')
    login_form.Userid = 'TestUser'
    login_form.Password = 'TestPassword'
    
    # submit login form
    agent.submit(login_form, login_form.buttons.first)
    

    根据this topic,您可能需要强制机械化才能使用SSLV3:

    page = Mechanize.new{|a| a.ssl_version, a.verify_mode = 'SSLv3', OpenSSL::SSL::VERIFY_NONE}.get "https://yourHTTPSurl"
    

    【讨论】:

    • OpenSSL::SSL::VERIFY_NONE 通常是个坏主意。我不清楚为什么敏感信息(如密码)会被发送到任何回答的服务器(而不是预期的服务器)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-19
    • 1970-01-01
    • 1970-01-01
    • 2019-11-18
    • 2015-06-08
    相关资源
    最近更新 更多