【问题标题】:ActionMailer SMTP "certificate verify failed"ActionMailer SMTP“证书验证失败”
【发布时间】:2016-07-30 20:32:12
【问题描述】:

我想从我的 Rails Web 应用程序发送电子邮件,并且我不想禁用 TLS 证书验证。但是由于某种原因,即使服务器证书有效,它总是会失败并显示“SSLv3 read server certificate B: certificate verify failed”。

我用openssl s_client(使用/etc/ssl/certs/ca-certificates.crt)进行了双重检查,并且在rails控制台中运行以下命令也可以,成功交付。

smtp = Net::SMTP.new(host, port)
smtp.enable_tls
smtp.start("localhost", username, password, :login) do |smtp|
  smtp.send_message msgstr, from, to
end

服务器有 Rails 4.2.6 和 Ruby 2.3.0

config.action_mailer.smtp_setting = {
    address: 
    port: 465,
    user_name: 
    password: 
    authentication: :login,
    openssl_verify_mode: OpenSSL::SSL::VERIFY_PEER,
    enable_starttls_auto: false,
    ssl: true
}

【问题讨论】:

    标签: ruby-on-rails ruby ssl smtp


    【解决方案1】:

    这个 Rails 配置适合我(使用 Ruby 2.2.2 和 Rails 5):

    ActionMailer::Base.smtp_setting = {
      ...
      enable_starttls_auto: true,
      openssl_verify_mode: OpenSSL::SSL::VERIFY_PEER,
      openssl_verify_depth: 3,  # if your CA is a sub signer
      ca_file: "/etc/ssl/certs/ca-certificates.crt",
      ...
    } 
    

    【讨论】:

      【解决方案2】:

      根据所描述的行为,我很确定尚未在控制台中完成对等验证,您需要明确在 Rails 配置中设置证书存储以验证对等证书

      为什么它在控制台中“有效”以及如何在控制台中实际验证对等点:

      观察到它在控制台中有效,但在 Rails 代码中无效,这是因为您的控制台代码中的 smtp.enable_tls不会强制对等验证,而您的 Rails 配置显然会这样做。实际上,当您将命令写入控制台时,您会打印出 SSLContext

      smtp.enable_tls
      # => #<OpenSSL::SSL::SSLContext:0x000000064043d0 @cert=nil, @key=nil,
             @client_ca=nil, @ca_file=nil, @ca_path=nil, @timeout=nil,
             @verify_mode=nil, @verify_depth=nil, @renegotiation_cb=nil,
             @verify_callback=nil, @cert_store=nil, @extra_chain_cert=nil, 
             @client_cert_cb=nil, @session_id_context=nil, @tmp_dh_callback=nil, 
             @session_get_cb=nil, @session_new_cb=nil, @session_remove_cb=nil, 
             @tmp_ecdh_callback=nil, @servername_cb=nil, @npn_protocols=nil, 
             @alpn_protocols=nil, @alpn_select_cb=nil, @npn_select_cb=nil>
      

      注意@verify_modenil,所以SSLContext 默认情况下没有启用对等验证。

      要在控制台中强制对等验证,以便您可以手动使用 SSL 设置,您需要使用自定义 SSLContext 并将其传递给 enable_tls

      ssl_context = Net::SMTP.default_ssl_context
      ssl_context.set_params
      smtp.enable_tls(ssl_context)
      # => #<OpenSSL::SSL::SSLContext:0x000000063c27c8 @cert=nil, @key=nil, 
             @client_ca=nil, @ca_file=nil, @ca_path=nil, @timeout=nil, 
             @verify_mode=1, @verify_depth=nil, @renegotiation_cb=nil, 
             @verify_callback=nil, @cert_store=#<OpenSSL::X509::Store:0x00000002894408 @verify_callback=nil, @error=nil, @error_string=nil, @chain=nil, @time=nil>, @extra_chain_cert=nil, 
             @client_cert_cb=nil, @session_id_context=nil, @tmp_dh_callback=nil, 
             @session_get_cb=nil, @session_new_cb=nil, @session_remove_cb=nil, 
             @tmp_ecdh_callback=nil, @servername_cb=nil, @npn_protocols=nil, 
             @alpn_protocols=nil, @alpn_select_cb=nil, @npn_select_cb=nil>
      

      仔细观察差异:SSLContext 现在将verify_mode 设置为 1,并且具有用于定义的验证的证书存储。这(除其他外)是SSLContext 中的set_params method 所做的。

      如何在 Rails 中配置证书存储

      现在,Rails 在为 SMTP 连接构造 SSLContext 时不会调用 set_params 方法。相反,它根据选项设置其上的各个属性(参见源代码中的herehere)。您已正确配置了要验证对等证书的 Rails,但您尚未配置证书存储来验证对等证书

      这可以使用 ca_fileca_path 选项来完成,因此以下 Rails 配置应该适合您:

      config.action_mailer.smtp_setting = {
          ...
          ssl: true
          enable_starttls_auto: false,
          openssl_verify_mode: OpenSSL::SSL::VERIFY_PEER,
          ca_file: "/etc/ssl/certs/ca-certificates.crt",
          ...
      } 
      

      我不知道为什么 Rails Guides 中没有正确记录这一点...

      【讨论】:

      • 以后在电脑上试试看,很好的解释。这是否适用于 Ruby/Rails 应用程序中的所有 TLS?我也有一些使用 Net::HTTP 和 use_ssl=true 的用法,并且假设这些也经过验证
      • 我不会说它适用于 Ruby 中的所有 SSL 请求。有时会设置验证(通常使用set_params 方法),有时则不会,如在 SMTP 中。所以我想一般情况下它是不同的。
      猜你喜欢
      • 2012-03-15
      • 2018-05-18
      • 2022-01-15
      • 2018-03-15
      • 2015-11-13
      • 2021-11-26
      • 2018-09-10
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多