diff options
author | Douwe Maan <douwe@selenight.nl> | 2019-04-21 13:03:26 +0300 |
---|---|---|
committer | Oswaldo Ferreira <oswaldo@gitlab.com> | 2019-05-30 16:47:31 +0300 |
commit | a9bcddee4c2653cbf2254d893299393e3778e7df (patch) | |
tree | 0c81c5358bce244da7cf9f9f684234a7f4a2dfd0 /config/initializers/http_hostname_override.rb | |
parent | 88241108c4d9807e5c312b11c910b3072bc6f120 (diff) |
Protect Gitlab::HTTP against DNS rebinding attack
Gitlab::HTTP now resolves the hostname only once, verifies the IP is not
blocked, and then uses the same IP to perform the actual request, while
passing the original hostname in the `Host` header and SSL SNI field.
Diffstat (limited to 'config/initializers/http_hostname_override.rb')
-rw-r--r-- | config/initializers/http_hostname_override.rb | 49 |
1 files changed, 49 insertions, 0 deletions
diff --git a/config/initializers/http_hostname_override.rb b/config/initializers/http_hostname_override.rb new file mode 100644 index 00000000000..58dd380326f --- /dev/null +++ b/config/initializers/http_hostname_override.rb @@ -0,0 +1,49 @@ +# This override allows passing `@hostname_override` to the SNI protocol, +# which is used to lookup the correct SSL certificate in the +# request handshake process. +# +# Given we've forced the HTTP request to be sent to the resolved +# IP address in a few scenarios (e.g.: `Gitlab::HTTP` through +# `Gitlab::UrlBlocker.validate!`), we need to provide the _original_ +# hostname via SNI in order to have a clean connection setup. +# +# This is ultimately needed in order to avoid DNS rebinding attacks +# through HTTP requests. +# +class OpenSSL::SSL::SSLContext + attr_accessor :hostname_override +end + +class OpenSSL::SSL::SSLSocket + module HostnameOverride + # rubocop: disable Gitlab/ModuleWithInstanceVariables + def hostname=(hostname) + super(@context.hostname_override || hostname) + end + + def post_connection_check(hostname) + super(@context.hostname_override || hostname) + end + # rubocop: enable Gitlab/ModuleWithInstanceVariables + end + + prepend HostnameOverride +end + +class Net::HTTP + attr_accessor :hostname_override + SSL_IVNAMES << :@hostname_override + SSL_ATTRIBUTES << :hostname_override + + module HostnameOverride + def addr_port + return super unless hostname_override + + addr = hostname_override + default_port = use_ssl? ? Net::HTTP.https_default_port : Net::HTTP.http_default_port + default_port == port ? addr : "#{addr}:#{port}" + end + end + + prepend HostnameOverride +end |