If you need to make an HTTPS connection to a host which uses an expired certificate, do not disable certificate verifications entirely. Doing that enables e.g. man in the middle attacks.
If you accept only a single expired and known certificate, you are much less in trouble.
Setup
All the solutions described below use a verify_callback
for the request's OpenSSL::X509::Store
where you can specify a lambda to adjust its verification response.
Your callback must return either true
or false
and OpenSSL's verification result is the first callback block argument.
In our examples, we will be connecting to expired.badssl.com
which uses an expired certificate.
The certificate is also a wildcard certificate, so its Common Name property (CN
) is set to *.badssl.com
.
Our verify_callback
will allow connecting to an expired host only when its certificate contains CN=*.badssl.com
.
uri = URI.parse('https://expired.badssl.com')
expected_common_name = '*.badssl.com'
verify_callback = lambda do |preverify_ok, store_context|
if store_context.error == OpenSSL::X509::V_ERR_CERT_HAS_EXPIRED && store_context.current_cert.subject.to_s.include?("CN=#{expected_common_name}")
# The certiciate for that host is expired, but it's fine for us.
true
else
preverify_ok
end
end
Using that is fairly straightforward in your favorite connection library. We've described a few below.
Net::HTTP
Ruby's Net::HTTP
requires the longest setup of all:
require 'net/https'
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
http.verify_callback = verify_callback
get = Net::HTTP::Get.new(uri.request_uri)
response = http.request(get)
puts response.body
HTTP
Using the
http
Show archive.org snapshot
gem, you can pass along the verify_callback
as an option like so:
require 'http'
response = HTTP.get(uri, ssl: { verify_callback: verify_callback })
puts response.body
RestClient
The
rest-client
Show archive.org snapshot
gem also offers an ssl_verify_callback
option, but not for its top-level utility methods, like RestClient.get
.
Instead, you can use a RestClient::Resource.new
like so:
require 'rest-client'
resource = RestClient::Resource.new(uri.to_s, ssl_verify_callback: verify_callback)
puts resource.get