diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/HeadersConfigurer.java b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/HeadersConfigurer.java index 6740525941e..abcdf331d3c 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/HeadersConfigurer.java +++ b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/HeadersConfigurer.java @@ -64,7 +64,7 @@ * X-Content-Type-Options: nosniff * Strict-Transport-Security: max-age=31536000 ; includeSubDomains * X-Frame-Options: DENY - * X-XSS-Protection: 1; mode=block + * X-XSS-Protection: 0 * * * @author Rob Winch @@ -73,6 +73,7 @@ * @author EddĂș MelĂ©ndez * @author Vedran Pavic * @author Ankur Pathak + * @author Daniel Garnier-Moiroux * @since 3.2 */ public class HeadersConfigurer> @@ -733,50 +734,6 @@ private XXssConfig() { enable(); } - /** - * If false, will not specify the mode as blocked. In this instance, any content - * will be attempted to be fixed. If true, the content will be replaced with "#". - * @param enabled the new value - * @deprecated use - * {@link XXssConfig#headerValue(XXssProtectionHeaderWriter.HeaderValue)} instead - */ - @Deprecated - public XXssConfig block(boolean enabled) { - this.writer.setBlock(enabled); - return this; - } - - /** - * If true, the header value will contain a value of 1. For example: - * - *
-		 * X-XSS-Protection: 1
-		 * 
- * - * or if {@link XXssProtectionHeaderWriter#setBlock(boolean)} of the given - * {@link XXssProtectionHeaderWriter} is true - * - * - *
-		 * X-XSS-Protection: 1; mode=block
-		 * 
- * - * If false, will explicitly disable specify that X-XSS-Protection is disabled. - * For example: - * - *
-		 * X-XSS-Protection: 0
-		 * 
- * @param enabled the new value - * @deprecated use - * {@link XXssConfig#headerValue(XXssProtectionHeaderWriter.HeaderValue)} instead - */ - @Deprecated - public XXssConfig xssProtectionEnabled(boolean enabled) { - this.writer.setEnabled(enabled); - return this; - } - /** * Sets the value of the X-XSS-PROTECTION header. OWASP recommends using * {@link XXssProtectionHeaderWriter.HeaderValue#DISABLED}. diff --git a/config/src/main/java/org/springframework/security/config/http/HeadersBeanDefinitionParser.java b/config/src/main/java/org/springframework/security/config/http/HeadersBeanDefinitionParser.java index 9a6ceeca9ba..7954c653706 100644 --- a/config/src/main/java/org/springframework/security/config/http/HeadersBeanDefinitionParser.java +++ b/config/src/main/java/org/springframework/security/config/http/HeadersBeanDefinitionParser.java @@ -69,10 +69,6 @@ public class HeadersBeanDefinitionParser implements BeanDefinitionParser { private static final String ATT_DISABLED = "disabled"; - private static final String ATT_ENABLED = "enabled"; - - private static final String ATT_BLOCK = "block"; - private static final String ATT_POLICY = "policy"; private static final String ATT_STRATEGY = "strategy"; @@ -583,20 +579,6 @@ private void parseXssElement(boolean addIfNotPresent, Element element, ParserCon BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(XXssProtectionHeaderWriter.class); if (xssElt != null) { boolean disabled = "true".equals(getAttribute(xssElt, ATT_DISABLED, "false")); - String enabled = xssElt.getAttribute(ATT_ENABLED); - if (StringUtils.hasText(enabled)) { - if (disabled) { - attrNotAllowed(parserContext, ATT_ENABLED, ATT_DISABLED, xssElt); - } - builder.addPropertyValue("enabled", enabled); - } - String block = xssElt.getAttribute(ATT_BLOCK); - if (StringUtils.hasText(block)) { - if (disabled) { - attrNotAllowed(parserContext, ATT_BLOCK, ATT_DISABLED, xssElt); - } - builder.addPropertyValue("block", block); - } XXssProtectionHeaderWriter.HeaderValue headerValue = XXssProtectionHeaderWriter.HeaderValue .from(xssElt.getAttribute(ATT_HEADER_VALUE)); if (headerValue != null) { diff --git a/config/src/main/java/org/springframework/security/config/web/server/ServerHttpSecurity.java b/config/src/main/java/org/springframework/security/config/web/server/ServerHttpSecurity.java index 7f7d38c5d19..994a48e321c 100644 --- a/config/src/main/java/org/springframework/security/config/web/server/ServerHttpSecurity.java +++ b/config/src/main/java/org/springframework/security/config/web/server/ServerHttpSecurity.java @@ -1040,7 +1040,7 @@ public ServerHttpSecurity oauth2ResourceServer( * X-Content-Type-Options: nosniff * Strict-Transport-Security: max-age=31536000 ; includeSubDomains * X-Frame-Options: DENY - * X-XSS-Protection: 1; mode=block + * X-XSS-Protection: 0 * * * such that "Strict-Transport-Security" is only added on secure requests. @@ -1081,7 +1081,7 @@ public HeaderSpec headers() { * X-Content-Type-Options: nosniff * Strict-Transport-Security: max-age=31536000 ; includeSubDomains * X-Frame-Options: DENY - * X-XSS-Protection: 1; mode=block + * X-XSS-Protection: 0 * * * such that "Strict-Transport-Security" is only added on secure requests. diff --git a/config/src/main/kotlin/org/springframework/security/config/annotation/web/headers/XssProtectionConfigDsl.kt b/config/src/main/kotlin/org/springframework/security/config/annotation/web/headers/XssProtectionConfigDsl.kt index a174b79c816..64c6904258b 100644 --- a/config/src/main/kotlin/org/springframework/security/config/annotation/web/headers/XssProtectionConfigDsl.kt +++ b/config/src/main/kotlin/org/springframework/security/config/annotation/web/headers/XssProtectionConfigDsl.kt @@ -25,18 +25,12 @@ import org.springframework.security.web.header.writers.XXssProtectionHeaderWrite * idiomatic Kotlin code. * * @author Eleftheria Stein + * @author Daniel Garnier-Moiroux * @since 5.3 - * @property block whether to specify the mode as blocked - * @property xssProtectionEnabled if true, the header value will contain a value of 1. - * If false, will explicitly disable specify that X-XSS-Protection is disabled. * @property headerValue the value of the X-XSS-Protection header. OWASP recommends [HeaderValue.DISABLED]. */ @HeadersSecurityMarker class XssProtectionConfigDsl { - @Deprecated("use headerValue instead") - var block: Boolean? = null - @Deprecated("use headerValue instead") - var xssProtectionEnabled: Boolean? = null var headerValue: HeaderValue? = null private var disabled = false @@ -50,8 +44,6 @@ class XssProtectionConfigDsl { internal fun get(): (HeadersConfigurer.XXssConfig) -> Unit { return { xssProtection -> - block?.also { xssProtection.block(block!!) } - xssProtectionEnabled?.also { xssProtection.xssProtectionEnabled(xssProtectionEnabled!!) } headerValue?.also { xssProtection.headerValue(headerValue) } if (disabled) { diff --git a/config/src/main/resources/org/springframework/security/config/spring-security-6.0.rnc b/config/src/main/resources/org/springframework/security/config/spring-security-6.0.rnc index 069705a5ffe..786b0777d73 100644 --- a/config/src/main/resources/org/springframework/security/config/spring-security-6.0.rnc +++ b/config/src/main/resources/org/springframework/security/config/spring-security-6.0.rnc @@ -1268,13 +1268,7 @@ xss-protection.attlist &= ## disable the X-XSS-Protection header. Default is 'false' meaning it is enabled. attribute disabled {xsd:boolean}? xss-protection.attlist &= - ## specify that XSS Protection should be explicitly enabled or disabled. Default is 'true' meaning it is enabled. - attribute enabled {xsd:boolean}? -xss-protection.attlist &= - ## Add mode=block to the header or not, default is on. - attribute block {xsd:boolean}? -xss-protection.attlist &= - ## Specify the value for the X-Xss-Protection header. When set, overrides both enabled and block attributes. + ## Specify the value for the X-Xss-Protection header. Defaults to "0". attribute header-value {"0"|"1"|"1; mode=block"}? content-type-options = diff --git a/config/src/main/resources/org/springframework/security/config/spring-security-6.0.xsd b/config/src/main/resources/org/springframework/security/config/spring-security-6.0.xsd index ec9b94b045c..32ca4c6192d 100644 --- a/config/src/main/resources/org/springframework/security/config/spring-security-6.0.xsd +++ b/config/src/main/resources/org/springframework/security/config/spring-security-6.0.xsd @@ -3553,23 +3553,9 @@ - - - specify that XSS Protection should be explicitly enabled or disabled. Default is 'true' - meaning it is enabled. - - - - - - Add mode=block to the header or not, default is on. - - - - Specify the value for the X-Xss-Protection header. When set, overrides both enabled and - block attributes. + Specify the value for the X-Xss-Protection header. Defaults to "0". diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configuration/HttpSecurityConfigurationTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configuration/HttpSecurityConfigurationTests.java index e808ac1aa6c..15d9d997971 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configuration/HttpSecurityConfigurationTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configuration/HttpSecurityConfigurationTests.java @@ -122,7 +122,7 @@ public void getWhenDefaultFilterChainBeanThenDefaultHeadersInResponse() throws E .andExpect(header().string(HttpHeaders.CACHE_CONTROL, "no-cache, no-store, max-age=0, must-revalidate")) .andExpect(header().string(HttpHeaders.EXPIRES, "0")) .andExpect(header().string(HttpHeaders.PRAGMA, "no-cache")) - .andExpect(header().string(HttpHeaders.X_XSS_PROTECTION, "1; mode=block")) + .andExpect(header().string(HttpHeaders.X_XSS_PROTECTION, "0")) .andReturn(); // @formatter:on assertThat(mvcResult.getResponse().getHeaderNames()).containsExactlyInAnyOrder( diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/HeadersConfigurerEagerHeadersTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/HeadersConfigurerEagerHeadersTests.java index e2f673a0bd1..30acb98a698 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/HeadersConfigurerEagerHeadersTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/HeadersConfigurerEagerHeadersTests.java @@ -57,7 +57,7 @@ public void requestWhenHeadersEagerlyConfiguredThenHeadersAreWritten() throws Ex .andExpect(header().string(HttpHeaders.CACHE_CONTROL, "no-cache, no-store, max-age=0, must-revalidate")) .andExpect(header().string(HttpHeaders.EXPIRES, "0")) .andExpect(header().string(HttpHeaders.PRAGMA, "no-cache")) - .andExpect(header().string("X-XSS-Protection", "1; mode=block")); + .andExpect(header().string("X-XSS-Protection", "0")); } @Configuration diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/HeadersConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/HeadersConfigurerTests.java index ca304bd0d2a..6d90b6f26d1 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/HeadersConfigurerTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/HeadersConfigurerTests.java @@ -80,7 +80,7 @@ public void getWhenHeadersConfiguredThenDefaultHeadersInResponse() throws Except .andExpect(header().string(HttpHeaders.CACHE_CONTROL, "no-cache, no-store, max-age=0, must-revalidate")) .andExpect(header().string(HttpHeaders.EXPIRES, "0")) .andExpect(header().string(HttpHeaders.PRAGMA, "no-cache")) - .andExpect(header().string(HttpHeaders.X_XSS_PROTECTION, "1; mode=block")).andReturn(); + .andExpect(header().string(HttpHeaders.X_XSS_PROTECTION, "0")).andReturn(); assertThat(mvcResult.getResponse().getHeaderNames()).containsExactlyInAnyOrder( HttpHeaders.X_CONTENT_TYPE_OPTIONS, HttpHeaders.X_FRAME_OPTIONS, HttpHeaders.STRICT_TRANSPORT_SECURITY, HttpHeaders.CACHE_CONTROL, HttpHeaders.EXPIRES, HttpHeaders.PRAGMA, HttpHeaders.X_XSS_PROTECTION); @@ -97,7 +97,7 @@ public void getWhenHeadersConfiguredInLambdaThenDefaultHeadersInResponse() throw .andExpect(header().string(HttpHeaders.CACHE_CONTROL, "no-cache, no-store, max-age=0, must-revalidate")) .andExpect(header().string(HttpHeaders.EXPIRES, "0")) .andExpect(header().string(HttpHeaders.PRAGMA, "no-cache")) - .andExpect(header().string(HttpHeaders.X_XSS_PROTECTION, "1; mode=block")).andReturn(); + .andExpect(header().string(HttpHeaders.X_XSS_PROTECTION, "0")).andReturn(); assertThat(mvcResult.getResponse().getHeaderNames()).containsExactlyInAnyOrder( HttpHeaders.X_CONTENT_TYPE_OPTIONS, HttpHeaders.X_FRAME_OPTIONS, HttpHeaders.STRICT_TRANSPORT_SECURITY, HttpHeaders.CACHE_CONTROL, HttpHeaders.EXPIRES, HttpHeaders.PRAGMA, HttpHeaders.X_XSS_PROTECTION); @@ -169,16 +169,16 @@ public void getWhenHeaderDefaultsDisabledAndXssProtectionConfiguredThenOnlyXssPr throws Exception { this.spring.register(XssProtectionConfig.class).autowire(); MvcResult mvcResult = this.mvc.perform(get("/").secure(true)) - .andExpect(header().string(HttpHeaders.X_XSS_PROTECTION, "1; mode=block")).andReturn(); + .andExpect(header().string(HttpHeaders.X_XSS_PROTECTION, "0")).andReturn(); assertThat(mvcResult.getResponse().getHeaderNames()).containsExactly(HttpHeaders.X_XSS_PROTECTION); } @Test - public void getWhenHeaderDefaultsDisabledAndXssProtectionConfiguredValueDisabledThenOnlyXssProtectionHeaderInResponse() + public void getWhenHeaderDefaultsDisabledAndXssProtectionConfiguredEnabledModeBlockThenOnlyXssProtectionHeaderInResponse() throws Exception { - this.spring.register(XssProtectionValueDisabledConfig.class).autowire(); + this.spring.register(XssProtectionValueEnabledModeBlockConfig.class).autowire(); MvcResult mvcResult = this.mvc.perform(get("/").secure(true)) - .andExpect(header().string(HttpHeaders.X_XSS_PROTECTION, "0")).andReturn(); + .andExpect(header().string(HttpHeaders.X_XSS_PROTECTION, "1; mode=block")).andReturn(); assertThat(mvcResult.getResponse().getHeaderNames()).containsExactly(HttpHeaders.X_XSS_PROTECTION); } @@ -186,16 +186,16 @@ public void getWhenHeaderDefaultsDisabledAndXssProtectionConfiguredValueDisabled public void getWhenOnlyXssProtectionConfiguredInLambdaThenOnlyXssProtectionHeaderInResponse() throws Exception { this.spring.register(XssProtectionInLambdaConfig.class).autowire(); MvcResult mvcResult = this.mvc.perform(get("/").secure(true)) - .andExpect(header().string(HttpHeaders.X_XSS_PROTECTION, "1; mode=block")).andReturn(); + .andExpect(header().string(HttpHeaders.X_XSS_PROTECTION, "0")).andReturn(); assertThat(mvcResult.getResponse().getHeaderNames()).containsExactly(HttpHeaders.X_XSS_PROTECTION); } @Test - public void getWhenHeaderDefaultsDisabledAndXssProtectionConfiguredValueDisabledInLambdaThenOnlyXssProtectionHeaderInResponse() + public void getWhenHeaderDefaultsDisabledAndXssProtectionConfiguredValueEnabledModeBlockInLambdaThenOnlyXssProtectionHeaderInResponse() throws Exception { - this.spring.register(XssProtectionValueDisabledInLambdaConfig.class).autowire(); + this.spring.register(XssProtectionValueEnabledModeBlockInLambdaConfig.class).autowire(); MvcResult mvcResult = this.mvc.perform(get("/").secure(true)) - .andExpect(header().string(HttpHeaders.X_XSS_PROTECTION, "0")).andReturn(); + .andExpect(header().string(HttpHeaders.X_XSS_PROTECTION, "1; mode=block")).andReturn(); assertThat(mvcResult.getResponse().getHeaderNames()).containsExactly(HttpHeaders.X_XSS_PROTECTION); } @@ -719,7 +719,7 @@ SecurityFilterChain filterChain(HttpSecurity http) throws Exception { @Configuration @EnableWebSecurity - static class XssProtectionValueDisabledConfig { + static class XssProtectionValueEnabledModeBlockConfig { @Bean SecurityFilterChain filterChain(HttpSecurity http) throws Exception { @@ -728,7 +728,7 @@ SecurityFilterChain filterChain(HttpSecurity http) throws Exception { .headers() .defaultsDisabled() .xssProtection() - .headerValue(XXssProtectionHeaderWriter.HeaderValue.DISABLED); + .headerValue(XXssProtectionHeaderWriter.HeaderValue.ENABLED_MODE_BLOCK); // @formatter:on return http.build(); } @@ -755,7 +755,7 @@ SecurityFilterChain filterChain(HttpSecurity http) throws Exception { @Configuration @EnableWebSecurity - static class XssProtectionValueDisabledInLambdaConfig { + static class XssProtectionValueEnabledModeBlockInLambdaConfig { @Bean SecurityFilterChain filterChain(HttpSecurity http) throws Exception { @@ -765,7 +765,7 @@ SecurityFilterChain filterChain(HttpSecurity http) throws Exception { headers .defaultsDisabled() .xssProtection((xXssConfig) -> - xXssConfig.headerValue(XXssProtectionHeaderWriter.HeaderValue.DISABLED) + xXssConfig.headerValue(XXssProtectionHeaderWriter.HeaderValue.ENABLED_MODE_BLOCK) ) ); // @formatter:on diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpHeadersTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpHeadersTests.java index e13ad004ab8..2b43794b0fe 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpHeadersTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpHeadersTests.java @@ -62,7 +62,7 @@ public class NamespaceHttpHeadersTests { defaultHeaders.put("Cache-Control", "no-cache, no-store, max-age=0, must-revalidate"); defaultHeaders.put("Expires", "0"); defaultHeaders.put("Pragma", "no-cache"); - defaultHeaders.put("X-XSS-Protection", "1; mode=block"); + defaultHeaders.put("X-XSS-Protection", "0"); } public final SpringTestContext spring = new SpringTestContext(this); @@ -116,7 +116,7 @@ public void requestWhenXssOnlyThenBehaviorMatchesNamespace() throws Exception { @Test public void requestWhenXssCustomThenBehaviorMatchesNamespace() throws Exception { this.spring.register(XssProtectionCustomConfig.class).autowire(); - this.mvc.perform(get("/")).andExpect(includes(Collections.singletonMap("X-XSS-Protection", "1"))); + this.mvc.perform(get("/")).andExpect(includes(Collections.singletonMap("X-XSS-Protection", "1; mode=block"))); } @Test @@ -291,7 +291,7 @@ SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // xss-protection@enabled and xss-protection@block .defaultsDisabled() .xssProtection() - .headerValue(XXssProtectionHeaderWriter.HeaderValue.ENABLED); + .headerValue(XXssProtectionHeaderWriter.HeaderValue.ENABLED_MODE_BLOCK); // @formatter:on return http.build(); } diff --git a/config/src/test/java/org/springframework/security/config/http/HttpHeadersConfigTests.java b/config/src/test/java/org/springframework/security/config/http/HttpHeadersConfigTests.java index eac36db7ff8..362475f63cf 100644 --- a/config/src/test/java/org/springframework/security/config/http/HttpHeadersConfigTests.java +++ b/config/src/test/java/org/springframework/security/config/http/HttpHeadersConfigTests.java @@ -62,7 +62,7 @@ public class HttpHeadersConfigTests { .put("Cache-Control", "no-cache, no-store, max-age=0, must-revalidate") .put("Expires", "0") .put("Pragma", "no-cache") - .put("X-XSS-Protection", "1; mode=block") + .put("X-XSS-Protection", "0") .build(); // @formatter:on @@ -351,32 +351,6 @@ public void requestWhenUsingXssProtectionThenDefaultsToModeBlock() throws Except excludedHeaders.remove("X-XSS-Protection"); this.spring.configLocations(this.xml("DefaultsDisabledWithXssProtection")).autowire(); // @formatter:off - this.mvc.perform(get("/")) - .andExpect(status().isOk()) - .andExpect(header().string("X-XSS-Protection", "1; mode=block")) - .andExpect(excludes(excludedHeaders)); - // @formatter:on - } - - @Test - public void requestWhenEnablingXssProtectionThenDefaultsToModeBlock() throws Exception { - Set excludedHeaders = new HashSet<>(defaultHeaders.keySet()); - excludedHeaders.remove("X-XSS-Protection"); - this.spring.configLocations(this.xml("DefaultsDisabledWithXssProtectionEnabled")).autowire(); - // @formatter:off - this.mvc.perform(get("/")) - .andExpect(status().isOk()) - .andExpect(header().string("X-XSS-Protection", "1; mode=block")) - .andExpect(excludes(excludedHeaders)); - // @formatter:on - } - - @Test - public void requestWhenDisablingXssProtectionThenDefaultsToZero() throws Exception { - Set excludedHeaders = new HashSet<>(defaultHeaders.keySet()); - excludedHeaders.remove("X-XSS-Protection"); - this.spring.configLocations(this.xml("DefaultsDisabledWithXssProtectionDisabled")).autowire(); - // @formatter:off this.mvc.perform(get("/")) .andExpect(status().isOk()) .andExpect(header().string("X-XSS-Protection", "0")) @@ -423,33 +397,6 @@ public void requestWhenSettingXssProtectionHeaderValueToOneModeBlockThenDefaults // @formatter:on } - @Test - public void requestWhenSettingXssProtectionDisabledHeaderValueToOneThenDefaultsToOne() throws Exception { - Set excludedHeaders = new HashSet<>(defaultHeaders.keySet()); - excludedHeaders.remove("X-XSS-Protection"); - this.spring.configLocations(this.xml("DefaultsDisabledWithXssProtectionDisabledAndHeaderValueOne")).autowire(); - // @formatter:off - this.mvc.perform(get("/")) - .andExpect(status().isOk()) - .andExpect(header().string("X-XSS-Protection", "1")) - .andExpect(excludes(excludedHeaders)); - // @formatter:on - } - - @Test - public void configureWhenXssProtectionDisabledAndBlockSetThenAutowireFails() { - /* - * NOTE: Original error message "Cannot set block to true with enabled false" no - * longer shows up in stack trace as of Spring Framework 6.x. - * - * See https://github.com/spring-projects/spring-framework/issues/25162. - */ - assertThatExceptionOfType(BeanCreationException.class) - .isThrownBy(() -> this.spring - .configLocations(this.xml("DefaultsDisabledWithXssProtectionDisabledAndBlockSet")).autowire()) - .havingRootCause().withMessageContaining("Property 'block' threw exception"); - } - @Test public void requestWhenUsingCacheControlThenRespondsWithCorrespondingHeaders() throws Exception { Map includedHeaders = ImmutableMap.builder() @@ -693,21 +640,6 @@ public void configureWhenHstsDisabledAndRequestMatcherSpecifiedThenAutowireFails .withMessageContaining("request-matcher-ref"); } - @Test - public void configureWhenXssProtectionDisabledAndEnabledThenAutowireFails() { - assertThatExceptionOfType(BeanDefinitionParsingException.class) - .isThrownBy(() -> this.spring.configLocations(this.xml("XssProtectionDisabledAndEnabled")).autowire()) - .withMessageContaining("enabled"); - } - - @Test - public void configureWhenXssProtectionDisabledAndBlockSpecifiedThenAutowireFails() { - assertThatExceptionOfType(BeanDefinitionParsingException.class) - .isThrownBy( - () -> this.spring.configLocations(this.xml("XssProtectionDisabledSpecifyingBlock")).autowire()) - .withMessageContaining("block"); - } - @Test public void configureWhenXssProtectionDisabledAndHeaderValueSpecifiedThenAutowireFails() { assertThatExceptionOfType(BeanDefinitionParsingException.class).isThrownBy( diff --git a/config/src/test/java/org/springframework/security/config/web/server/HeaderSpecTests.java b/config/src/test/java/org/springframework/security/config/web/server/HeaderSpecTests.java index 001b965d96a..32b694899ac 100644 --- a/config/src/test/java/org/springframework/security/config/web/server/HeaderSpecTests.java +++ b/config/src/test/java/org/springframework/security/config/web/server/HeaderSpecTests.java @@ -75,7 +75,7 @@ public void setup() { this.expectedHeaders.add(HttpHeaders.EXPIRES, "0"); this.expectedHeaders.add(ContentTypeOptionsServerHttpHeadersWriter.X_CONTENT_OPTIONS, "nosniff"); this.expectedHeaders.add(XFrameOptionsServerHttpHeadersWriter.X_FRAME_OPTIONS, "DENY"); - this.expectedHeaders.add(XXssProtectionServerHttpHeadersWriter.X_XSS_PROTECTION, "1 ; mode=block"); + this.expectedHeaders.add(XXssProtectionServerHttpHeadersWriter.X_XSS_PROTECTION, "0"); } @Test diff --git a/config/src/test/kotlin/org/springframework/security/config/annotation/web/HeadersDslTests.kt b/config/src/test/kotlin/org/springframework/security/config/annotation/web/HeadersDslTests.kt index 0c19ff76b9b..f3929d4fca9 100644 --- a/config/src/test/kotlin/org/springframework/security/config/annotation/web/HeadersDslTests.kt +++ b/config/src/test/kotlin/org/springframework/security/config/annotation/web/HeadersDslTests.kt @@ -62,7 +62,7 @@ class HeadersDslTests { header { string(HttpHeaders.CACHE_CONTROL, "no-cache, no-store, max-age=0, must-revalidate") } header { string(HttpHeaders.EXPIRES, "0") } header { string(HttpHeaders.PRAGMA, "no-cache") } - header { string(XXssProtectionServerHttpHeadersWriter.X_XSS_PROTECTION, "1; mode=block") } + header { string(XXssProtectionServerHttpHeadersWriter.X_XSS_PROTECTION, "0") } } } diff --git a/config/src/test/kotlin/org/springframework/security/config/annotation/web/HttpSecurityDslTests.kt b/config/src/test/kotlin/org/springframework/security/config/annotation/web/HttpSecurityDslTests.kt index c397bbc5cbe..bdb849e83a6 100644 --- a/config/src/test/kotlin/org/springframework/security/config/annotation/web/HttpSecurityDslTests.kt +++ b/config/src/test/kotlin/org/springframework/security/config/annotation/web/HttpSecurityDslTests.kt @@ -106,7 +106,7 @@ class HttpSecurityDslTests { string(HttpHeaders.PRAGMA, "no-cache") } header { - string(XXssProtectionServerHttpHeadersWriter.X_XSS_PROTECTION, "1; mode=block") + string(XXssProtectionServerHttpHeadersWriter.X_XSS_PROTECTION, "0") } } } diff --git a/config/src/test/kotlin/org/springframework/security/config/annotation/web/headers/XssProtectionConfigDslTests.kt b/config/src/test/kotlin/org/springframework/security/config/annotation/web/headers/XssProtectionConfigDslTests.kt index 84cf4a5f6f8..aa18da0c0e5 100644 --- a/config/src/test/kotlin/org/springframework/security/config/annotation/web/headers/XssProtectionConfigDslTests.kt +++ b/config/src/test/kotlin/org/springframework/security/config/annotation/web/headers/XssProtectionConfigDslTests.kt @@ -36,6 +36,7 @@ import org.springframework.test.web.servlet.get * Tests for [XssProtectionConfigDsl] * * @author Eleftheria Stein + * @author Daniel Garnier-Moiroux */ @ExtendWith(SpringTestContextExtension::class) class XssProtectionConfigDslTests { @@ -52,7 +53,7 @@ class XssProtectionConfigDslTests { this.mockMvc.get("/") { secure = true }.andExpect { - header { string(XXssProtectionServerHttpHeadersWriter.X_XSS_PROTECTION, "1; mode=block") } + header { string(XXssProtectionServerHttpHeadersWriter.X_XSS_PROTECTION, "0") } } } @@ -72,26 +73,25 @@ class XssProtectionConfigDslTests { } @Test - fun `headers when XSS protection with block false then mode is not block in header`() { - this.spring.register(XssProtectionBlockFalseConfig::class.java).autowire() + fun `headers when XSS protection disabled then X-XSS-Protection header not in response`() { + this.spring.register(XssProtectionDisabledFunctionConfig::class.java).autowire() this.mockMvc.get("/") { secure = true }.andExpect { - header { string(XXssProtectionServerHttpHeadersWriter.X_XSS_PROTECTION, "1") } + header { doesNotExist(XXssProtectionServerHttpHeadersWriter.X_XSS_PROTECTION) } } } @Configuration @EnableWebSecurity - open class XssProtectionBlockFalseConfig { + open class XssProtectionDisabledFunctionConfig { @Bean open fun securityFilterChain(http: HttpSecurity): SecurityFilterChain { http { headers { - defaultsDisabled = true xssProtection { - block = false + disable() } } } @@ -100,53 +100,26 @@ class XssProtectionConfigDslTests { } @Test - fun `headers when XSS protection disabled then X-XSS-Protection header is 0`() { - this.spring.register(XssProtectionDisabledConfig::class.java).autowire() + fun `headers when XSS protection header value enabled then X-XSS-Protection header is 1`() { + this.spring.register(XssProtectionHeaderValueEnabledFunctionConfig::class.java).autowire() this.mockMvc.get("/") { secure = true }.andExpect { - header { string(XXssProtectionServerHttpHeadersWriter.X_XSS_PROTECTION, "0") } + header { string(XXssProtectionServerHttpHeadersWriter.X_XSS_PROTECTION, "1") } } } @Configuration @EnableWebSecurity - open class XssProtectionDisabledConfig { + open class XssProtectionHeaderValueEnabledFunctionConfig { @Bean open fun securityFilterChain(http: HttpSecurity): SecurityFilterChain { http { headers { defaultsDisabled = true xssProtection { - xssProtectionEnabled = false - } - } - } - return http.build() - } - } - - @Test - fun `headers when XSS protection disabled then X-XSS-Protection header not in response`() { - this.spring.register(XssProtectionDisabledFunctionConfig::class.java).autowire() - - this.mockMvc.get("/") { - secure = true - }.andExpect { - header { doesNotExist(XXssProtectionServerHttpHeadersWriter.X_XSS_PROTECTION) } - } - } - - @Configuration - @EnableWebSecurity - open class XssProtectionDisabledFunctionConfig { - @Bean - open fun securityFilterChain(http: HttpSecurity): SecurityFilterChain { - http { - headers { - xssProtection { - disable() + headerValue = XXssProtectionHeaderWriter.HeaderValue.ENABLED } } } @@ -155,26 +128,26 @@ class XssProtectionConfigDslTests { } @Test - fun `headers when XSS protection header value disabled then X-XSS-Protection header is 0`() { - this.spring.register(XssProtectionHeaderValueDisabledFunctionConfig::class.java).autowire() + fun `headers when XSS protection header value enabled_mode_block then X-XSS-Protection header is 1 and mode=block`() { + this.spring.register(XssProtectionHeaderValueEnabledModeBlockFunctionConfig::class.java).autowire() this.mockMvc.get("/") { secure = true }.andExpect { - header { string(XXssProtectionServerHttpHeadersWriter.X_XSS_PROTECTION, "0") } + header { string(XXssProtectionServerHttpHeadersWriter.X_XSS_PROTECTION, "1; mode=block") } } } @Configuration @EnableWebSecurity - open class XssProtectionHeaderValueDisabledFunctionConfig () { + open class XssProtectionHeaderValueEnabledModeBlockFunctionConfig { @Bean open fun securityFilterChain(http: HttpSecurity): SecurityFilterChain { http { headers { defaultsDisabled = true xssProtection { - headerValue = XXssProtectionHeaderWriter.HeaderValue.DISABLED + headerValue = XXssProtectionHeaderWriter.HeaderValue.ENABLED_MODE_BLOCK } } } diff --git a/config/src/test/kotlin/org/springframework/security/config/web/server/ServerHeadersDslTests.kt b/config/src/test/kotlin/org/springframework/security/config/web/server/ServerHeadersDslTests.kt index 33e84e89241..dfa78726cac 100644 --- a/config/src/test/kotlin/org/springframework/security/config/web/server/ServerHeadersDslTests.kt +++ b/config/src/test/kotlin/org/springframework/security/config/web/server/ServerHeadersDslTests.kt @@ -71,7 +71,7 @@ class ServerHeadersDslTests { .expectHeader().valueEquals(HttpHeaders.CACHE_CONTROL, "no-cache, no-store, max-age=0, must-revalidate") .expectHeader().valueEquals(HttpHeaders.EXPIRES, "0") .expectHeader().valueEquals(HttpHeaders.PRAGMA, "no-cache") - .expectHeader().valueEquals(XXssProtectionServerHttpHeadersWriter.X_XSS_PROTECTION, "1 ; mode=block") + .expectHeader().valueEquals(XXssProtectionServerHttpHeadersWriter.X_XSS_PROTECTION, "0") } @Configuration diff --git a/config/src/test/kotlin/org/springframework/security/config/web/server/ServerHttpSecurityDslTests.kt b/config/src/test/kotlin/org/springframework/security/config/web/server/ServerHttpSecurityDslTests.kt index 366e03f1338..52dd70ad6b7 100644 --- a/config/src/test/kotlin/org/springframework/security/config/web/server/ServerHttpSecurityDslTests.kt +++ b/config/src/test/kotlin/org/springframework/security/config/web/server/ServerHttpSecurityDslTests.kt @@ -126,7 +126,7 @@ class ServerHttpSecurityDslTests { .expectHeader().valueEquals(HttpHeaders.CACHE_CONTROL, "no-cache, no-store, max-age=0, must-revalidate") .expectHeader().valueEquals(HttpHeaders.EXPIRES, "0") .expectHeader().valueEquals(HttpHeaders.PRAGMA, "no-cache") - .expectHeader().valueEquals(XXssProtectionServerHttpHeadersWriter.X_XSS_PROTECTION, "1 ; mode=block") + .expectHeader().valueEquals(XXssProtectionServerHttpHeadersWriter.X_XSS_PROTECTION, "0") } @Configuration diff --git a/config/src/test/kotlin/org/springframework/security/config/web/server/ServerXssProtectionDslTests.kt b/config/src/test/kotlin/org/springframework/security/config/web/server/ServerXssProtectionDslTests.kt index 9fdfcc378ee..30e21307ee5 100644 --- a/config/src/test/kotlin/org/springframework/security/config/web/server/ServerXssProtectionDslTests.kt +++ b/config/src/test/kotlin/org/springframework/security/config/web/server/ServerXssProtectionDslTests.kt @@ -57,7 +57,7 @@ class ServerXssProtectionDslTests { this.client.get() .uri("/") .exchange() - .expectHeader().valueEquals(XXssProtectionServerHttpHeadersWriter.X_XSS_PROTECTION, "1 ; mode=block") + .expectHeader().valueEquals(XXssProtectionServerHttpHeadersWriter.X_XSS_PROTECTION, "0") } @Configuration @@ -107,7 +107,7 @@ class ServerXssProtectionDslTests { this.client.get() .uri("/") .exchange() - .expectHeader().valueEquals(XXssProtectionServerHttpHeadersWriter.X_XSS_PROTECTION, "0") + .expectHeader().valueEquals(XXssProtectionServerHttpHeadersWriter.X_XSS_PROTECTION, "1") } @EnableWebFluxSecurity @@ -118,7 +118,7 @@ class ServerXssProtectionDslTests { return http { headers { xssProtection { - headerValue = XXssProtectionServerHttpHeadersWriter.HeaderValue.DISABLED + headerValue = XXssProtectionServerHttpHeadersWriter.HeaderValue.ENABLED } } } diff --git a/config/src/test/resources/org/springframework/security/config/http/HttpHeadersConfigTests-DefaultsDisabledWithXssProtectionDisabled.xml b/config/src/test/resources/org/springframework/security/config/http/HttpHeadersConfigTests-DefaultsDisabledWithXssProtectionDisabled.xml deleted file mode 100644 index 92253a5e46e..00000000000 --- a/config/src/test/resources/org/springframework/security/config/http/HttpHeadersConfigTests-DefaultsDisabledWithXssProtectionDisabled.xml +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - - - - - - - - - - - diff --git a/config/src/test/resources/org/springframework/security/config/http/HttpHeadersConfigTests-DefaultsDisabledWithXssProtectionDisabledAndBlockSet.xml b/config/src/test/resources/org/springframework/security/config/http/HttpHeadersConfigTests-DefaultsDisabledWithXssProtectionDisabledAndBlockSet.xml deleted file mode 100644 index 818f7171137..00000000000 --- a/config/src/test/resources/org/springframework/security/config/http/HttpHeadersConfigTests-DefaultsDisabledWithXssProtectionDisabledAndBlockSet.xml +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - - - - - - - - - - - diff --git a/config/src/test/resources/org/springframework/security/config/http/HttpHeadersConfigTests-DefaultsDisabledWithXssProtectionDisabledAndHeaderValueOne.xml b/config/src/test/resources/org/springframework/security/config/http/HttpHeadersConfigTests-DefaultsDisabledWithXssProtectionDisabledAndHeaderValueOne.xml deleted file mode 100644 index 093c19c58cc..00000000000 --- a/config/src/test/resources/org/springframework/security/config/http/HttpHeadersConfigTests-DefaultsDisabledWithXssProtectionDisabledAndHeaderValueOne.xml +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - - - - - - - - - - - diff --git a/config/src/test/resources/org/springframework/security/config/http/HttpHeadersConfigTests-DefaultsDisabledWithXssProtectionEnabled.xml b/config/src/test/resources/org/springframework/security/config/http/HttpHeadersConfigTests-DefaultsDisabledWithXssProtectionEnabled.xml deleted file mode 100644 index ac228ffa82d..00000000000 --- a/config/src/test/resources/org/springframework/security/config/http/HttpHeadersConfigTests-DefaultsDisabledWithXssProtectionEnabled.xml +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - - - - - - - - - - - diff --git a/config/src/test/resources/org/springframework/security/config/http/HttpHeadersConfigTests-XssProtectionDisabledAndEnabled.xml b/config/src/test/resources/org/springframework/security/config/http/HttpHeadersConfigTests-XssProtectionDisabledAndEnabled.xml deleted file mode 100644 index d555f0a0b04..00000000000 --- a/config/src/test/resources/org/springframework/security/config/http/HttpHeadersConfigTests-XssProtectionDisabledAndEnabled.xml +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - - - - - - - - - - - diff --git a/config/src/test/resources/org/springframework/security/config/http/HttpHeadersConfigTests-XssProtectionDisabledSpecifyingBlock.xml b/config/src/test/resources/org/springframework/security/config/http/HttpHeadersConfigTests-XssProtectionDisabledSpecifyingBlock.xml deleted file mode 100644 index 6cbfe14d597..00000000000 --- a/config/src/test/resources/org/springframework/security/config/http/HttpHeadersConfigTests-XssProtectionDisabledSpecifyingBlock.xml +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - - - - - - - - - - - diff --git a/docs/modules/ROOT/pages/features/exploits/headers.adoc b/docs/modules/ROOT/pages/features/exploits/headers.adoc index 6c308499873..a8c71220d06 100644 --- a/docs/modules/ROOT/pages/features/exploits/headers.adoc +++ b/docs/modules/ROOT/pages/features/exploits/headers.adoc @@ -33,7 +33,7 @@ Expires: 0 X-Content-Type-Options: nosniff Strict-Transport-Security: max-age=31536000 ; includeSubDomains X-Frame-Options: DENY -X-XSS-Protection: 1; mode=block +X-XSS-Protection: 0 ---- ==== @@ -209,18 +209,14 @@ See the relevant sections to see how to customize the defaults for both xref:ser ==== Some browsers have built-in support for filtering out https://www.owasp.org/index.php/Testing_for_Reflected_Cross_site_scripting_(OWASP-DV-001)[reflected XSS attacks]. -This is by no means foolproof but does assist in XSS protection. +The filter has been deprecated in major browsers, and https://cheatsheetseries.owasp.org/cheatsheets/HTTP_Headers_Cheat_Sheet.html#x-xss-protection[current OWASP recommendation] is to explicitly set the header to 0. -The filtering is typically enabled by default, so adding the header typically just ensures it is enabled and instructs the browser what to do when a XSS attack is detected. -For example, the filter might try to change the content in the least invasive way to still render everything. -At times, this type of replacement can become an https://hackademix.net/2009/11/21/ies-xss-filter-creates-xss-vulnerabilities/[XSS vulnerability in itself]. -Instead, it is best to block the content rather than attempt to fix it. By default, Spring Security blocks the content by using the following header: ==== [source] ---- -X-XSS-Protection: 1; mode=block +X-XSS-Protection: 0 ---- ==== diff --git a/docs/modules/ROOT/pages/reactive/exploits/headers.adoc b/docs/modules/ROOT/pages/reactive/exploits/headers.adoc index 06baa5ad3f6..629cd73692a 100644 --- a/docs/modules/ROOT/pages/reactive/exploits/headers.adoc +++ b/docs/modules/ROOT/pages/reactive/exploits/headers.adoc @@ -255,8 +255,8 @@ fun webFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain { [[webflux-headers-xss-protection]] == X-XSS-Protection -By default, Spring Security instructs browsers to block reflected XSS attacks by using the <. -You can disable `X-XSS-Protection`: +By default, Spring Security instructs browsers to disable the XSS Auditor by using <. +You can disable the `X-XSS-Protection` header entirely: .X-XSS-Protection Customization ==== @@ -291,6 +291,41 @@ fun webFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain { ---- ==== +You can also change the header value: + +.X-XSS-Protection Explicit header value +==== +.Java +[source,java,role="primary"] +---- +@Bean +SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) { + http + // ... + .headers(headers -> headers + .xssProtection(xssProtection -> xssProtection.headerValue(XXssProtectionServerHttpHeadersWriter.HeaderValue.ENABLED_MODE_BLOCK)) + ); + return http.build(); +} +---- + +.Kotlin +[source,kotlin,role="secondary"] +---- +@Bean +fun webFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain { + return http { + // ... + headers { + xssProtection { + headerValue = XXssProtectionServerHttpHeadersWriter.HeaderValue.ENABLED_MODE_BLOCK + } + } + } +} +---- +==== + [[webflux-headers-csp]] == Content Security Policy (CSP) By default, Spring Security does not add xref:features/exploits/headers.adoc#headers-csp[Content Security Policy], because a reasonable default is impossible to know without the context of the application. diff --git a/docs/modules/ROOT/pages/servlet/appendix/namespace/http.adoc b/docs/modules/ROOT/pages/servlet/appendix/namespace/http.adoc index ae5f139fda1..29de571e37e 100644 --- a/docs/modules/ROOT/pages/servlet/appendix/namespace/http.adoc +++ b/docs/modules/ROOT/pages/servlet/appendix/namespace/http.adoc @@ -571,23 +571,10 @@ This is in no-way a full protection to XSS attacks! Do not include the header for https://en.wikipedia.org/wiki/Cross-site_scripting#Non-Persistent[reflected / Type-1 Cross-Site Scripting (XSS)] protection. -[[nsa-xss-protection-enabled]] -* **xss-protection-enabled** -Explicitly enable or disable https://en.wikipedia.org/wiki/Cross-site_scripting#Non-Persistent[reflected / Type-1 Cross-Site Scripting (XSS)] protection. - - -[[nsa-xss-protection-block]] -* **xss-protection-block** -When true and xss-protection-enabled is true, adds mode=block to the header. -This indicates to the browser that the page should not be loaded at all. -When false and xss-protection-enabled is true, the page will still be rendered when an reflected attack is detected but the response will be modified to protect against the attack. -Note that there are sometimes ways of bypassing this mode which can often times make blocking the page more desirable. - [[nsa-xss-protection-header-value]] * **xss-protection-header-value** Explicitly set the value for https://en.wikipedia.org/wiki/Cross-site_scripting#Non-Persistent[reflected / Type-1 Cross-Site Scripting (XSS)] header. -One of: "0", "1", "1; mode=block". -When set, overrides both enabled and block attributes. +One of: "0", "1", "1; mode=block". Defaults to "0". [[nsa-xss-protection-parents]] diff --git a/docs/modules/ROOT/pages/servlet/exploits/headers.adoc b/docs/modules/ROOT/pages/servlet/exploits/headers.adoc index b7de0428d7e..40022773097 100644 --- a/docs/modules/ROOT/pages/servlet/exploits/headers.adoc +++ b/docs/modules/ROOT/pages/servlet/exploits/headers.adoc @@ -529,9 +529,10 @@ class SecurityConfig { [[servlet-headers-xss-protection]] == X-XSS-Protection -By default, Spring Security instructs browsers to block reflected XSS attacks by using the <. +By default, Spring Security instructs browsers to disable the XSS Auditor by using <. However, you can change this default. -For example, the following configuration specifies that Spring Security should no longer instruct browsers to block the content: +For example, the following configuration specifies that Spring Security instruct compatible browsers to enable filtering, +and block the content: .X-XSS-Protection Customization ==== @@ -548,7 +549,7 @@ public class WebSecurityConfig { // ... .headers(headers -> headers .xssProtection(xss -> xss - .block(false) + .headerValue(XXssProtectionHeaderWriter.HeaderValue.ENABLED_MODE_BLOCK) ) ); return http.build(); @@ -563,7 +564,7 @@ public class WebSecurityConfig { - + ---- @@ -581,7 +582,7 @@ class SecurityConfig { http { headers { xssProtection { - block = false + headerValue = XXssProtectionHeaderWriter.HeaderValue.ENABLED_MODE_BLOCK } } } diff --git a/web/src/main/java/org/springframework/security/web/header/writers/XXssProtectionHeaderWriter.java b/web/src/main/java/org/springframework/security/web/header/writers/XXssProtectionHeaderWriter.java index 4c6b3e101fe..2ead1769037 100644 --- a/web/src/main/java/org/springframework/security/web/header/writers/XXssProtectionHeaderWriter.java +++ b/web/src/main/java/org/springframework/security/web/header/writers/XXssProtectionHeaderWriter.java @@ -29,6 +29,7 @@ * * @author Rob Winch * @author Ankur Pathak + * @author Daniel Garnier-Moiroux * @since 3.2 */ public final class XXssProtectionHeaderWriter implements HeaderWriter { @@ -41,7 +42,7 @@ public final class XXssProtectionHeaderWriter implements HeaderWriter { * Create a new instance */ public XXssProtectionHeaderWriter() { - this.headerValue = HeaderValue.ENABLED_MODE_BLOCK; + this.headerValue = HeaderValue.DISABLED; } @Override @@ -51,55 +52,6 @@ public void writeHeaders(HttpServletRequest request, HttpServletResponse respons } } - /** - * If true, will contain a value of 1. For example: - * - *
-	 * X-XSS-Protection: 1
-	 * 
- * - * or if {@link #setBlock(boolean)} is true - * - * - *
-	 * X-XSS-Protection: 1; mode=block
-	 * 
- * - * If false, will explicitly disable specify that X-XSS-Protection is disabled. For - * example: - * - *
-	 * X-XSS-Protection: 0
-	 * 
- * @param enabled the new value - * @deprecated use {@link XXssProtectionHeaderWriter#setHeaderValue(HeaderValue)} - * instead - */ - @Deprecated - public void setEnabled(boolean enabled) { - if (!enabled) { - this.headerValue = HeaderValue.DISABLED; - } - else if (this.headerValue == HeaderValue.DISABLED) { - this.headerValue = HeaderValue.ENABLED; - } - } - - /** - * If false, will not specify the mode as blocked. In this instance, any content will - * be attempted to be fixed. If true, the content will be replaced with "#". - * @param block the new value - * @deprecated use {@link XXssProtectionHeaderWriter#setHeaderValue(HeaderValue)} - * instead - */ - @Deprecated - public void setBlock(boolean block) { - if (this.headerValue == HeaderValue.DISABLED && block) { - throw new IllegalArgumentException("Cannot set block to true with enabled false"); - } - this.headerValue = block ? HeaderValue.ENABLED_MODE_BLOCK : HeaderValue.ENABLED; - } - /** * Sets the value of the X-XSS-PROTECTION header. *

diff --git a/web/src/main/java/org/springframework/security/web/server/header/XXssProtectionServerHttpHeadersWriter.java b/web/src/main/java/org/springframework/security/web/server/header/XXssProtectionServerHttpHeadersWriter.java index 7caa214358a..6c2a4afd7d3 100644 --- a/web/src/main/java/org/springframework/security/web/server/header/XXssProtectionServerHttpHeadersWriter.java +++ b/web/src/main/java/org/springframework/security/web/server/header/XXssProtectionServerHttpHeadersWriter.java @@ -41,7 +41,7 @@ public class XXssProtectionServerHttpHeadersWriter implements ServerHttpHeadersW * Creates a new instance */ public XXssProtectionServerHttpHeadersWriter() { - this.headerValue = HeaderValue.ENABLED_MODE_BLOCK; + this.headerValue = HeaderValue.DISABLED; updateDelegate(); } @@ -51,57 +51,8 @@ public Mono writeHttpHeaders(ServerWebExchange exchange) { } /** - * If true, will contain a value of 1. For example: - * - *

-	 * X-XSS-Protection: 1
-	 * 
- * - * or if {@link #setBlock(boolean)} is true - * - * - *
-	 * X-XSS-Protection: 1; mode=block
-	 * 
- * - * If false, will explicitly disable specify that X-XSS-Protection is disabled. For - * example: - * - *
-	 * X-XSS-Protection: 0
-	 * 
- * @param enabled the new value - * @deprecated use - * {@link XXssProtectionServerHttpHeadersWriter#setHeaderValue(HeaderValue)} instead - */ - @Deprecated - public void setEnabled(boolean enabled) { - if (!enabled) { - this.headerValue = HeaderValue.DISABLED; - } - else if (this.headerValue == HeaderValue.DISABLED) { - this.headerValue = HeaderValue.ENABLED; - } - updateDelegate(); - } - - /** - * If false, will not specify the mode as blocked. In this instance, any content will - * be attempted to be fixed. If true, the content will be replaced with "#". - * @param block the new value - * @deprecated use - * {@link XXssProtectionServerHttpHeadersWriter#setHeaderValue(HeaderValue)} instead - */ - @Deprecated - public void setBlock(boolean block) { - Assert.isTrue(this.headerValue != HeaderValue.DISABLED || !block, - "Cannot set block to true with enabled false"); - this.headerValue = block ? HeaderValue.ENABLED_MODE_BLOCK : HeaderValue.ENABLED; - updateDelegate(); - } - - /** - * Sets the value of the X-XSS-PROTECTION header. + * Sets the value of the X-XSS-PROTECTION header. Defaults to + * {@link HeaderValue#DISABLED} *

* If {@link HeaderValue#DISABLED}, will specify that X-XSS-Protection is disabled. * For example: diff --git a/web/src/test/java/org/springframework/security/web/header/writers/XXssProtectionHeaderWriterTests.java b/web/src/test/java/org/springframework/security/web/header/writers/XXssProtectionHeaderWriterTests.java index 9245ae0135a..c534ef547f0 100644 --- a/web/src/test/java/org/springframework/security/web/header/writers/XXssProtectionHeaderWriterTests.java +++ b/web/src/test/java/org/springframework/security/web/header/writers/XXssProtectionHeaderWriterTests.java @@ -28,6 +28,7 @@ /** * @author Rob Winch * @author Ankur Pathak + * @author Daniel Garnier-Moiroux * */ public class XXssProtectionHeaderWriterTests { @@ -49,43 +50,11 @@ public void setup() { @Test public void writeHeaders() { - this.writer.writeHeaders(this.request, this.response); - assertThat(this.response.getHeaderNames()).hasSize(1); - assertThat(this.response.getHeaderValues("X-XSS-Protection")).containsOnly("1; mode=block"); - } - - @Test - public void writeHeadersNoBlock() { - this.writer.setBlock(false); - this.writer.writeHeaders(this.request, this.response); - assertThat(this.response.getHeaderNames()).hasSize(1); - assertThat(this.response.getHeaderValues("X-XSS-Protection")).containsOnly("1"); - } - - @Test - public void writeHeadersDisabled() { - this.writer.setBlock(false); - this.writer.setEnabled(false); - this.writer.writeHeaders(this.request, this.response); - assertThat(this.response.getHeaderNames()).hasSize(1); - assertThat(this.response.getHeaderValues("X-XSS-Protection")).containsOnly("0"); - } - - @Test - public void setEnabledFalseWithBlockTrue() { - this.writer.setEnabled(false); this.writer.writeHeaders(this.request, this.response); assertThat(this.response.getHeaderNames()).hasSize(1); assertThat(this.response.getHeaderValues("X-XSS-Protection")).containsOnly("0"); } - @Test - public void setBlockTrueWithEnabledFalse() { - this.writer.setBlock(false); - this.writer.setEnabled(false); - assertThatIllegalArgumentException().isThrownBy(() -> this.writer.setBlock(true)); - } - @Test public void writeHeaderWhenNotPresent() { String value = new String("value"); diff --git a/web/src/test/java/org/springframework/security/web/server/header/XXssProtectionServerHttpHeadersWriterTests.java b/web/src/test/java/org/springframework/security/web/server/header/XXssProtectionServerHttpHeadersWriterTests.java index 7445810a9fb..a8e8624b78b 100644 --- a/web/src/test/java/org/springframework/security/web/server/header/XXssProtectionServerHttpHeadersWriterTests.java +++ b/web/src/test/java/org/springframework/security/web/server/header/XXssProtectionServerHttpHeadersWriterTests.java @@ -46,23 +46,6 @@ void setHeaderValueNullThenThrowsIllegalArgumentException() { @Test public void writeHeadersWhenNoHeadersThenWriteHeaders() { - this.writer.writeHttpHeaders(this.exchange); - assertThat(this.headers).hasSize(1); - assertThat(this.headers.get(XXssProtectionServerHttpHeadersWriter.X_XSS_PROTECTION)) - .containsOnly("1 ; mode=block"); - } - - @Test - public void writeHeadersWhenBlockFalseThenWriteHeaders() { - this.writer.setBlock(false); - this.writer.writeHttpHeaders(this.exchange); - assertThat(this.headers).hasSize(1); - assertThat(this.headers.get(XXssProtectionServerHttpHeadersWriter.X_XSS_PROTECTION)).containsOnly("1"); - } - - @Test - public void writeHeadersWhenEnabledFalseThenWriteHeaders() { - this.writer.setEnabled(false); this.writer.writeHttpHeaders(this.exchange); assertThat(this.headers).hasSize(1); assertThat(this.headers.get(XXssProtectionServerHttpHeadersWriter.X_XSS_PROTECTION)).containsOnly("0");