Skip to content

Instantly share code, notes, and snippets.

@tam7t
Last active April 14, 2022 10:57
Show Gist options
  • Save tam7t/86eb4793e8ecf3f55037 to your computer and use it in GitHub Desktop.
Save tam7t/86eb4793e8ecf3f55037 to your computer and use it in GitHub Desktop.
Securing Ruby's OpenSSL

Are your Ruby HTTPS API calls secure?

Let's check:

2.0.0-p481 :001 > OpenSSL::SSL::SSLContext::DEFAULT_PARAMS
 => {:ssl_version=>"SSLv23", :verify_mode=>1, :ciphers=>"ALL:!ADH:!EXPORT:!SSLv2:RC4+RSA:+HIGH:+MEDIUM:+LOW", :options=>-2147482625}
2.0.0-p481 :002 > rating = JSON.parse(RestClient::Resource.new("https://www.howsmyssl.com/a/check" ).get)['rating']
 => "Bad"

Fix it!

2.0.0-p481 :003 > OpenSSL::SSL::SSLContext::DEFAULT_PARAMS[:options] |= OpenSSL::SSL::OP_NO_COMPRESSION
 => -2147351553
2.0.0-p481 :004 > OpenSSL::SSL::SSLContext::DEFAULT_PARAMS[:ciphers] = "TLSv1.2:!aNULL:!eNULL"
 => "TLSv1.2:!aNULL:!eNULL"
2.0.0-p481 :005 > OpenSSL::SSL::SSLContext::DEFAULT_PARAMS[:ssl_version] ="TLSv1_2"
 => "TLSv1_2"
2.0.0-p481 :006 > rating = JSON.parse(RestClient::Resource.new("https://www.howsmyssl.com/a/check" ).get)['rating']
 => "Probably Okay"

Explanation

OpenSSL::SSL::OP_NO_COMPRESSION protects against CRIME.

TLSv1.2:!aNULL:!eNULL defines the set of cipher suites that your client will use during negotiation. This ensures that insecure cipher suites are not included. OpenSSL::SSL::OP_NO_SSLv2 and OpenSSL::SSL::OP_NO_SSLv3 as well

TLSv1_2 does nothing as this is just a preference. The set of ciphers we chose will only work with TLSv1.2. To explicitly disable SSLv2 and SSLv3 you can additionally set OpenSSL::SSL::OP_NO_SSLv2 and OpenSSL::SSL::OP_NO_SSLv3. TLSv1.2 and its ciphers will protect against POODLE, BEAST.

But does my OpenSSL have vulnerabilities?

Let's find out what version we're on:

2.0.0-p481 :007 > OpenSSL::OPENSSL_VERSION
 => "OpenSSL 1.0.1g 7 Apr 2014"

Then check the openssl vulnerabilities page or search the NIST CVE database for your version of OpenSSL.

Protip: CPE format: cpe:/:openssl:openssl:1.0.1g

That's not good. I installed ruby with RVM and openssl with homebrew so I need to update both:

~ $ brew update
~ $ brew upgrade openssl
~ $ brew link openssl --force
~ $ rvm reinstall all --with-openssl-dir=/usr/local/opt/openssl/lib

I had problems with --autolibs=homebrew not linking to my homebrew openssl, but the --with-openssl-dir option fixed that.

Notes

Forcing TLSv1.2 may break your app. To see the list of supported ciphers you can use a webservice like...

JSON.parse(Faraday.get("https://www.howsmyssl.com/a/check").body)['given_cipher_suites']

or OpenSSL::Cipher.ciphers. I've found the web service to be more informative.

Hope that helps. I'd be very interested if there are better ways to do this or information I'm missing. Hit me up on twitter @tam7t or leave a comment below.

@tpickett66
Copy link

The approach for setting the options bitmask under fix it may end up leaving you more vulnerable due to actually disabling other security options. A better approach is:

OpenSSL::SSL::SSLContext::DEFAULT_PARAMS[:options] |= OpenSSL::SSL::OP_NO_SSLv2
=> -2130705409
OpenSSL::SSL::SSLContext::DEFAULT_PARAMS[:options] |= OpenSSL::SSL::OP_NO_SSLv3
=> -2097150977
OpenSSL::SSL::SSLContext::DEFAULT_PARAMS[:options] |= OpenSSL::SSL::OP_NO_COMPRESSION
=> -2097019905

This preserves any other options that have been enabled. See also SSLConfig in nahi/httpclient.

@tam7t
Copy link
Author

tam7t commented Apr 26, 2015

@tpickett66 thanks for pointing that out!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment