mirror of
https://github.com/elastic/logstash.git
synced 2025-04-24 14:47:19 -04:00
Improve default security for SSLContext with a monkeypatch.
New defaults: * Cipher suite based on Mozilla's Intermediate set from https://wiki.mozilla.org/Security/Server_Side_TLS (at time of writing) * Disable SSLv2 explicitly * Disable SSLv3 explicitly * Disable compression if possible The SSL option setting came from the ruby-ftw library's FTW::Connection (apache 2 licensed, I am author), and transitively through work published by jmhodges to improve Ruby's SSL strength. I include specs to ensure we never include export or weak ciphers by default. Using this patch to test the security improvements according to `www.howsmyssl.com` shows much improved results: --- Testing this: ``` ruby -r ./lib/logstash/patches/stronger_openssl_defaults.rb -ropenssl -rsocket -rjson -rawesome_print -e 'c = OpenSSL::SSL::SSLContext.new; t = TCPSocket.new("www.howsmyssl.com", 443); o = OpenSSL::SSL::SSLSocket.new(t, c); o.connect; o.puts "GET /a/check HTTP/1.1\r\nHost: www.howsmyssl.com\r\n\r\n"; headers,body = o.read.split("\r\n\r\n", 2); puts body' ``` (I processed the JSON output w/ jq for easier reading) The purpose of the above is to test the default behavior of SSLContext. * JRuby 1.7.19 w/ this patch reports no cipher problems. * JRuby 1.7.19 without this patch has several weak ciphers used: ``` "TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA: [\"uses keys smaller than 128 bits in its encryption\"]", "TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA: [\"uses keys smaller than 128 bits in its encryption\"]", "TLS_DHE_RSA_WITH_DES_CBC_SHA: [\"uses keys smaller than 128 bits in its encryption\"]", "TLS_RSA_EXPORT_WITH_DES40_CBC_SHA: [\"uses keys smaller than 128 bits in its encryption\"]", "TLS_RSA_EXPORT_WITH_RC4_40_MD5: [\"uses keys smaller than 128 bits in its encryption\",\"use RC4 which has insecure biases in its output\"]", "TLS_RSA_WITH_DES_CBC_SHA: [\"uses keys smaller than 128 bits in its encryption\"]", "TLS_RSA_WITH_RC4_128_MD5: [\"use RC4 which has insecure biases in its output\"]", "TLS_RSA_WITH_RC4_128_SHA: [\"use RC4 which has insecure biases in its output\"]" ``` Under MRI, similar cipher selection problems are observed without this patch (weak export ciphers, other weak small-key ciphers, RC4 complaints). With this patch, no cipher complaints are reported by www.howsmyssl.com One other note: Because JRuby defaults to TLS 1.0 and only makes CBC ciphers available under the Mozilla Intermediate cipher set, I believe (and howsmyssl.com agrees) that these defaults still make the BEAST exploit a problem. Switching to TLS 1.1 should fix this, but we need to do more research to determine the what, if any, impact it will have if we force TLS 1.1 to be the default.. Fixes #3579
This commit is contained in:
parent
f7b76fa2ae
commit
fbf8e1e320
3 changed files with 88 additions and 0 deletions
|
@ -1,3 +1,4 @@
|
|||
require "logstash/patches/bugfix_jruby_2558"
|
||||
require "logstash/patches/cabin"
|
||||
require "logstash/patches/profile_require_calls"
|
||||
require "logstash/patches/stronger_openssl_defaults"
|
||||
|
|
62
lib/logstash/patches/stronger_openssl_defaults.rb
Normal file
62
lib/logstash/patches/stronger_openssl_defaults.rb
Normal file
|
@ -0,0 +1,62 @@
|
|||
|
||||
require "openssl"
|
||||
|
||||
# :nodoc:
|
||||
class OpenSSL::SSL::SSLContext
|
||||
# Wrap SSLContext.new to a stronger default settings.
|
||||
class << self
|
||||
alias_method :orig_new, :new
|
||||
def new(*args)
|
||||
c = orig_new(*args)
|
||||
|
||||
# MRI nor JRuby seem to actually invoke `SSLContext#set_params` by
|
||||
# default, which makes the default ciphers (and other settings) not
|
||||
# actually defaults. Oops!
|
||||
# To force this, and force our (hopefully more secure) defaults on
|
||||
# all things using openssl in Ruby, we will invoke set_params
|
||||
# on all new SSLContext objects.
|
||||
c.set_params
|
||||
c
|
||||
end
|
||||
end
|
||||
|
||||
# This cipher selection comes from https://wiki.mozilla.org/Security/Server_Side_TLS
|
||||
MOZILLA_INTERMEDIATE_CIPHERS = "ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA"
|
||||
|
||||
# Returns the value that should be used for the default SSLContext options
|
||||
#
|
||||
# This is a method instead of a constant because some constants (like
|
||||
# OpenSSL::SSL::OP_NO_COMPRESSION) may not be available in all Ruby
|
||||
# versions/platforms.
|
||||
def self.__default_options
|
||||
# ruby-core is refusing to patch ruby's default openssl settings to be more
|
||||
# secure, so let's fix that here. The next few lines setting options and
|
||||
# ciphers come from jmhodges' proposed patch
|
||||
ssloptions = OpenSSL::SSL::OP_ALL
|
||||
|
||||
# TODO(sissel): JRuby doesn't have this. Maybe work on a fix?
|
||||
if defined?(OpenSSL::SSL::OP_DONT_INSERT_EMPTY_FRAGMENTS)
|
||||
ssloptions &= ~OpenSSL::SSL::OP_DONT_INSERT_EMPTY_FRAGMENTS
|
||||
end
|
||||
|
||||
# TODO(sissel): JRuby doesn't have this. Maybe work on a fix?
|
||||
if defined?(OpenSSL::SSL::OP_NO_COMPRESSION)
|
||||
ssloptions |= OpenSSL::SSL::OP_NO_COMPRESSION
|
||||
end
|
||||
|
||||
# Disable SSLv2 and SSLv3. They are insecure and highly discouraged.
|
||||
ssloptions |= OpenSSL::SSL::OP_NO_SSLv2 if defined?(OpenSSL::SSL::OP_NO_SSLv2)
|
||||
ssloptions |= OpenSSL::SSL::OP_NO_SSLv3 if defined?(OpenSSL::SSL::OP_NO_SSLv3)
|
||||
ssloptions
|
||||
end
|
||||
|
||||
# Overwriting the DEFAULT_PARAMS const idea from here: https://www.ruby-lang.org/en/news/2014/10/27/changing-default-settings-of-ext-openssl/
|
||||
remove_const(:DEFAULT_PARAMS) if const_defined?(:DEFAULT_PARAMS)
|
||||
DEFAULT_PARAMS = {
|
||||
:ssl_version => "SSLv23",
|
||||
:verify_mode => OpenSSL::SSL::VERIFY_PEER,
|
||||
:ciphers => MOZILLA_INTERMEDIATE_CIPHERS,
|
||||
:options => __default_options # Not a constant because it's computed at start-time.
|
||||
}
|
||||
|
||||
end
|
25
spec/logstash/patches_spec.rb
Normal file
25
spec/logstash/patches_spec.rb
Normal file
|
@ -0,0 +1,25 @@
|
|||
require "logstash/patches"
|
||||
|
||||
describe "OpenSSL defaults" do
|
||||
subject { OpenSSL::SSL::SSLContext.new }
|
||||
|
||||
# OpenSSL::SSL::SSLContext#ciphers returns an array of
|
||||
# [ [ ciphername, version, bits, alg_bits ], [ ... ], ... ]
|
||||
|
||||
# List of cipher names
|
||||
let(:ciphers) { subject.ciphers.map(&:first) }
|
||||
|
||||
# List of cipher encryption bit strength.
|
||||
let(:encryption_bits) { subject.ciphers.map { |_, _, _, a| a } }
|
||||
|
||||
it "should not include any export ciphers" do
|
||||
# SSLContext#ciphers returns an array of [ciphername, tlsversion, key_bits, alg_bits]
|
||||
# Let's just check the cipher names
|
||||
expect(ciphers).not_to be_any { |name| name =~ /EXPORT/ || name =~ /^EXP/ }
|
||||
end
|
||||
|
||||
it "should not include any weak ciphers (w/ less than 128 bits in encryption algorithm)" do
|
||||
# SSLContext#ciphers returns an array of [ciphername, tlsversion, key_bits, alg_bits]
|
||||
expect(encryption_bits).not_to be_any { |bits| bits < 128 }
|
||||
end
|
||||
end
|
Loading…
Add table
Add a link
Reference in a new issue