【问题标题】:How to verify server SSL certificate?如何验证服务器 SSL 证书?
【发布时间】:2018-05-24 12:57:30
【问题描述】:

我是 SSL 概念的新手,我正在尝试使用 HTTParty 连接到具有 x509 相互身份验证的 API。

我得到了客户端证书、客户端密钥和服务器证书(都是 pem 文件)。

我让它与客户端证书和密钥以及verify: false 一起使用。

现在下一步是如何验证服务器证书?

HTTParty 文档链接https://github.com/jnunemaker/httparty/tree/master/docs#working-with-ssl

class ServiceClient
  include HTTParty
  DEFAULT_HEADERS = {
    'Content-Type' => 'application/json'
  }.freeze
  base_uri 'https://example.com'
  pem File.read("#{File.expand_path('.')}/path/to/certs/cert.pem")

  def self.iframe_url(**payload)
    post(
     '/test/create',
     body: payload.to_json,
     headers: DEFAULT_HEADERS,
     verify: false
    )
  end
end

调用服务客户端

payload = {user_id: "100", account_id: "1234"} 
ServiceClient.iframe_url(payload)

编辑:

HTTParty 不是硬性要求,因此任何 http 客户端的解决方案都对我有用。

如果我删除 verify: false 我会得到以下错误。

OpenSSL::SSL::SSLError: SSL_connect returned=1 errno=0 state=error: certificate verify failed

【问题讨论】:

  • 这段代码缺少很多上下文,常量、变量和方法调用与iframe_url方法之间的关系还不清楚。
  • 添加了更多细节。我只是在寻找有关如何指定服务器证书并验证对它的响应的指针。 HTTParty 文档没有这方面的任何细节。我想答案可能很简单,但我找不到任何关于如何做的参考。谢谢。
  • 你可以用File.read(File.expand_path('./path/to/certs/cert.pem))`来代替它。无需插入字符串。
  • HTTParty 是否允许您获取服务器证书以进行验证?我知道它是一个非常好的“快速和简单”集成库,但我不确定它是否那么复杂。
  • 我认为可以,但不自信。代码显示 cert_store 参数可以通过选项发送。

标签: ruby-on-rails ruby httpclient httparty


【解决方案1】:

默认情况下,TLS 协议只向服务器证明服务器的身份 客户端,将客户端的身份验证留给服务器 应用层,例如 HTTP Basic 身份验证。

相互 TLS 身份验证是指客户端和服务器分别进行身份验证 其他同时。它可以用作 HTTP Basic 的替代品 验证。它通常也称为基于证书的身份验证。

看起来您遇到了这个错误(但适用于verify: false),因为 服务器证书不受信任。是自签吗?或者也许是 颁发证书的证书颁发机构 (CA) 在您的系统中不受信任。

HTTParty 建立在Net::HTTP 之上,它使用OpenSSL,它获取 来自系统的可信 CA 证书,例如/etc/ssl/cert.pem。虽然你 可以覆盖SSL_CERT_FILE 环境变量,我不认为这是一个 好主意,因为它可能会影响应用程序的其他部分。一个更好的 解决方案是将 CA 证书仅传递给 HTTParty。

我从未使用过 HTTParty,所​​以请耐心等待。但是快速浏览一下 code 并假设您使用默认的ConnectionAdapter,看起来您需要 定义 pemssl_ca_file 选项,这将定义客户端 和 CA 证书文件。另请注意,这样做,it will turn certificate verification on.

class ServiceClient
  include HTTParty
  pem "path/to/client_cert_and_key.pem"
  ssl_ca_file "path/to/ca_certificates.pem"
end

我认为这与您的问题无关,但如果您的客户端密钥有 密码,请务必将其传递给pem(pem_contents, password)

HTH。最好的。

【讨论】:

    【解决方案2】:

    试一试,我想您正在使用要验证的 ssl 证书。在 RestClient 中也很容易,我在最后添加了 sn-p。

    class ServiceClient
      include HTTParty
      DEFAULT_HEADERS = {
        'Content-Type' => 'application/json'
      }.freeze
      base_uri 'https://example.com'
      ssl_ca_file "#{File.expand_path('.')}/path/to/certs/cert.pem"
    
    
      def self.iframe_url(**payload)
        post(
         '/test/create',
         body: payload.to_json,
         headers: DEFAULT_HEADERS,
        )
      end
    end
    

    Rest Client 解决方案:

    client = RestClient::Resource.new('https://example.com/',
                                  :ssl_client_cert => p12.certificate,
                                  :ssl_client_key => p12.key,
                                  :verify_ssl => OpenSSL::SSL::VERIFY_NONE)
    

    【讨论】:

    • OpenSSL::SSL::VERIFY_NONE 不验证 SSL,对吗?问题是如何验证它。
    【解决方案3】:

    这应该可以解决问题:

    RestClient::Resource.new(
      'https://example.com',
      :ssl_client_cert  =>  OpenSSL::X509::Certificate.new(File.read("cert.pem")),
      :ssl_client_key   =>  OpenSSL::PKey::RSA.new(File.read("key.pem"), "passphrase, if any"),
      :ssl_ca_file      =>  "ca_certificate.pem",
      :verify_ssl       =>  OpenSSL::SSL::VERIFY_PEER
    ).get
    

    参考:https://github.com/rest-client/rest-client

    【讨论】:

      【解决方案4】:

      使用“OpenSSL::SSL::VERIFY_PEER = OpenSSL::SSL::VERIFY_NONE”

      在你的代码中,可能看起来像:

          class ServiceClient
            include HTTParty
            OpenSSL::SSL::VERIFY_PEER = OpenSSL::SSL::VERIFY_NONE
            {...your code...}
          end
      

      【讨论】:

      • 这违背了目的,因为它绕过了服务器证书验证。
      • 你在重新定义常量VERIFY_PEER吗?主要WTF!
      猜你喜欢
      • 2010-09-09
      • 2012-11-14
      • 2015-06-24
      • 1970-01-01
      • 2015-05-11
      • 2014-08-02
      • 1970-01-01
      • 2016-05-24
      • 2021-12-16
      相关资源
      最近更新 更多