From 5a92a8bd1b28dde9f2a1f50af53dcc03cec383ab Mon Sep 17 00:00:00 2001 From: Simon Brandhof Date: Wed, 6 May 2015 22:55:40 +0200 Subject: [PATCH] SONAR-6537 Add HTTP security headers --- .../platform/SecurityServletFilter.java | 12 +++++++ .../platform/SecurityServletFilterTest.java | 6 ++-- .../main/webapp/WEB-INF/config/environment.rb | 36 +++++++++++++++++-- 3 files changed, 50 insertions(+), 4 deletions(-) diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/SecurityServletFilter.java b/server/sonar-server/src/main/java/org/sonar/server/platform/SecurityServletFilter.java index 33d1c9d19d5..f4d3b486a27 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/platform/SecurityServletFilter.java +++ b/server/sonar-server/src/main/java/org/sonar/server/platform/SecurityServletFilter.java @@ -29,6 +29,10 @@ import javax.servlet.http.HttpServletResponse; import java.io.IOException; +/** + * This servlet filter sets response headers that enable browser protection against several classes if Web attacks. + * The list of headers is mirrored in environment.rb as a workaround to Rack swallowing the headers.. + */ public class SecurityServletFilter implements Filter { @Override @@ -44,6 +48,14 @@ public class SecurityServletFilter implements Filter { // See https://www.owasp.org/index.php/Clickjacking_Protection_for_Java_EE HttpServletResponse httpResponse = (HttpServletResponse) resp; httpResponse.addHeader("X-Frame-Options", "SAMEORIGIN"); + + // Cross-site scripting + // See https://www.owasp.org/index.php/List_of_useful_HTTP_headers + httpResponse.addHeader("X-XSS-Protection", "1; mode=block"); + + // MIME-sniffing + // See https://www.owasp.org/index.php/List_of_useful_HTTP_headers + httpResponse.addHeader("X-Content-Type-Options", "nosniff"); } @Override diff --git a/server/sonar-server/src/test/java/org/sonar/server/platform/SecurityServletFilterTest.java b/server/sonar-server/src/test/java/org/sonar/server/platform/SecurityServletFilterTest.java index 8bc547a5646..79edf760566 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/platform/SecurityServletFilterTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/platform/SecurityServletFilterTest.java @@ -26,7 +26,10 @@ import javax.servlet.FilterConfig; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import static org.mockito.Matchers.anyString; +import static org.mockito.Matchers.startsWith; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; public class SecurityServletFilterTest { @@ -41,8 +44,7 @@ public class SecurityServletFilterTest { FilterChain chain = mock(FilterChain.class); filter.doFilter(request, response, chain); - // Clickjacking - verify(response).addHeader("X-Frame-Options", "SAMEORIGIN"); + verify(response, times(3)).addHeader(startsWith("X-"), anyString()); filter.destroy(); } diff --git a/server/sonar-web/src/main/webapp/WEB-INF/config/environment.rb b/server/sonar-web/src/main/webapp/WEB-INF/config/environment.rb index 20db504e78b..c5c7739fd05 100644 --- a/server/sonar-web/src/main/webapp/WEB-INF/config/environment.rb +++ b/server/sonar-web/src/main/webapp/WEB-INF/config/environment.rb @@ -52,6 +52,37 @@ class EagerPluginLoader < Rails::Plugin::Loader end end + +# +# Put response headers on all HTTP calls. This is done by the Java SecurityServlerFilter, +# but for some reason Rack swallows the headers set on Java side. +# See middleware configuration below. +# +class SecurityHeaders + def initialize(app) + @app = app + end + + def call(env) + status, headers, body = @app.call(env) + + # Clickjacking protection + # See https://www.owasp.org/index.php/Clickjacking_Protection_for_Java_EE + headers['X-Frame-Options']='SAMEORIGIN' + + # Cross-site scripting + # See https://www.owasp.org/index.php/List_of_useful_HTTP_headers + headers['X-XSS-Protection']='1; mode=block' + + # MIME-sniffing + # See https://www.owasp.org/index.php/List_of_useful_HTTP_headers + headers['X-Content-Type-Options']='nosniff'; + + [status, headers, body] + end +end + + Rails::Initializer.run do |config| # Settings in config/environments/* take precedence over those specified here. # Application configuration should go into files in config/initializers @@ -108,6 +139,9 @@ Rails::Initializer.run do |config| # Activate observers that should always be running # Please note that observers generated using script/generate observer need to have an _observer suffix # config.active_record.observers = :cacher, :garbage_collector, :forum_observer + + # Add security related headers + config.middleware.use SecurityHeaders end @@ -283,5 +317,3 @@ DatabaseVersion.automatic_setup # Increase size of form parameters # See http://jira.codehaus.org/browse/SONAR-5577 Rack::Utils.key_space_limit = 262144 # 4 times the default size - - -- 2.39.5