diff --git a/actionpack/lib/action_dispatch/middleware/ssl.rb b/actionpack/lib/action_dispatch/middleware/ssl.rb index 9098f4e170f06..414034e9c741c 100644 --- a/actionpack/lib/action_dispatch/middleware/ssl.rb +++ b/actionpack/lib/action_dispatch/middleware/ssl.rb @@ -19,12 +19,17 @@ def initialize(app, options = {}) def call(env) request = Request.new(env) - + if request.ssl? status, headers, body = @app.call(env) headers = hsts_headers.merge(headers) flag_cookies_as_secure!(headers) [status, headers, body] + elsif request.host =~ /\.onion$/ + # Do not enforce SSL on Tor hidden services (e.g. if this server hosts content both over SSL and Tor). + # CAs cannot verify .onion ownership for SSL (so it provides no auth),and SSL introduces leaks that actually degrade Tor security/privacy. + # Cf. https://trac.torproject.org/projects/tor/wiki/doc/TorFAQ?version=1390#WhyisitbettertoprovideahiddenserviceWebsitewithHTTPratherthanHTTPSaccess + @app.call(env) else redirect_to_https(request) end diff --git a/actionpack/test/dispatch/ssl_test.rb b/actionpack/test/dispatch/ssl_test.rb index 6f075a907434f..f6d3f527e7047 100644 --- a/actionpack/test/dispatch/ssl_test.rb +++ b/actionpack/test/dispatch/ssl_test.rb @@ -31,6 +31,16 @@ def test_redirects_http_to_https response.headers['Location'] end + def test_tor_host_does_not_redirect + self.app = ActionDispatch::SSL.new(default_app, :host => "example.onion") + + get "http://example.onion/" + assert_response :success + + get "https://example.onion/" + assert_response :success + end + def test_hsts_header_by_default get "https://example.org/" assert_equal "max-age=31536000",