2014年9月22日 星期一

SSL_connect returned=1 errno=0 state=SSLv3 read server certificate B: certificate verify failed

使用open uri執行https的網址, 發生了SSL_connect returned=1 errno=0 state=SSLv3 read server certificate B: certificate verify failed的錯誤!!!

google找了一些solution:
1. http://stackoverflow.com/questions/5711190/how-to-get-rid-of-opensslsslsslerror
2. http://stackoverflow.com/questions/10728436/opensslsslsslerror-ssl-connect-returned-1-errno-0-state-sslv3-read-server-c
3. http://jimneath.org/2011/10/19/ruby-ssl-certificate-verify-failed.html

主要是嘗試了config/initializers/fix_ssl.rb的方法(參照第3個連結):
require 'open-uri'
require 'net/https'

module Net
  class HTTP
    alias_method :original_use_ssl=, :use_ssl=
    
    def use_ssl=(flag)
      self.ca_file = Rails.root.join('lib/ca-bundle.crt')
      self.verify_mode = OpenSSL::SSL::VERIFY_PEER
      self.original_use_ssl = flag
    end
  end
end
但問題仍然無法解決...


重新正視問題, 發現有SSL憑證的網址(ex: https://www.facebook.com/), 不會出現錯誤; 沒有SSL憑證的網址, 在browser也會出現憑證錯誤或未受信任(不安全)的連線等等的警告頁面, 這類網址才會出現錯誤~~問題可以釐清了!!

一開始找的solution方向比較偏向certification authority certificates(CA Certs)過期或找不到的狀況, 而現在真正要解決的狀況是讓沒有SSL憑證的網址不要出現錯誤...所以不要做驗證不就好了嗎:P

OpenSSL::SSL::VERIFY_NONE就是關鍵
網路上找到一些方案, 有滿多是全域性的設定, 但並非所有https都不做驗證, 所以此法不妥~~~
那要怎麼樣才能針對目前要連的網址不做驗證呢?
在open uri時, 設定驗證模式就搞定了...
require 'open-uri'

open(uri, ssl_verify_mode: OpenSSL::SSL::VERIFY_NONE)
問題找對方向, 沒想到這麼簡單就解決了XD


也可以用Net::HTTP來取代open uri的用法
require 'net/https'

http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true if uri.scheme == "https"  # enable SSL/TLS
http.verify_mode = OpenSSL::SSL::VERIFY_NONE # important!!!
http.start {
  http.request_get(uri.path) { |res| 
    print res.body
  }
}

若有遇到相似問題的人, 以上方法可以參考看看囉:)

1 則留言: