ソースを参照

Default X-Xss-Protection header value to "0"

Closes gh-9631
Daniel Garnier-Moiroux 2 年 前
コミット
27059ced87
32 ファイル変更105 行追加637 行削除
  1. 2 45
      config/src/main/java/org/springframework/security/config/annotation/web/configurers/HeadersConfigurer.java
  2. 0 18
      config/src/main/java/org/springframework/security/config/http/HeadersBeanDefinitionParser.java
  3. 2 2
      config/src/main/java/org/springframework/security/config/web/server/ServerHttpSecurity.java
  4. 1 9
      config/src/main/kotlin/org/springframework/security/config/annotation/web/headers/XssProtectionConfigDsl.kt
  5. 1 7
      config/src/main/resources/org/springframework/security/config/spring-security-6.0.rnc
  6. 1 15
      config/src/main/resources/org/springframework/security/config/spring-security-6.0.xsd
  7. 1 1
      config/src/test/java/org/springframework/security/config/annotation/web/configuration/HttpSecurityConfigurationTests.java
  8. 1 1
      config/src/test/java/org/springframework/security/config/annotation/web/configurers/HeadersConfigurerEagerHeadersTests.java
  9. 14 14
      config/src/test/java/org/springframework/security/config/annotation/web/configurers/HeadersConfigurerTests.java
  10. 3 3
      config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpHeadersTests.java
  11. 1 69
      config/src/test/java/org/springframework/security/config/http/HttpHeadersConfigTests.java
  12. 1 1
      config/src/test/java/org/springframework/security/config/web/server/HeaderSpecTests.java
  13. 1 1
      config/src/test/kotlin/org/springframework/security/config/annotation/web/HeadersDslTests.kt
  14. 1 1
      config/src/test/kotlin/org/springframework/security/config/annotation/web/HttpSecurityDslTests.kt
  15. 17 44
      config/src/test/kotlin/org/springframework/security/config/annotation/web/headers/XssProtectionConfigDslTests.kt
  16. 1 1
      config/src/test/kotlin/org/springframework/security/config/web/server/ServerHeadersDslTests.kt
  17. 1 1
      config/src/test/kotlin/org/springframework/security/config/web/server/ServerHttpSecurityDslTests.kt
  18. 3 3
      config/src/test/kotlin/org/springframework/security/config/web/server/ServerXssProtectionDslTests.kt
  19. 0 37
      config/src/test/resources/org/springframework/security/config/http/HttpHeadersConfigTests-DefaultsDisabledWithXssProtectionDisabled.xml
  20. 0 37
      config/src/test/resources/org/springframework/security/config/http/HttpHeadersConfigTests-DefaultsDisabledWithXssProtectionDisabledAndBlockSet.xml
  21. 0 37
      config/src/test/resources/org/springframework/security/config/http/HttpHeadersConfigTests-DefaultsDisabledWithXssProtectionDisabledAndHeaderValueOne.xml
  22. 0 37
      config/src/test/resources/org/springframework/security/config/http/HttpHeadersConfigTests-DefaultsDisabledWithXssProtectionEnabled.xml
  23. 0 37
      config/src/test/resources/org/springframework/security/config/http/HttpHeadersConfigTests-XssProtectionDisabledAndEnabled.xml
  24. 0 37
      config/src/test/resources/org/springframework/security/config/http/HttpHeadersConfigTests-XssProtectionDisabledSpecifyingBlock.xml
  25. 3 7
      docs/modules/ROOT/pages/features/exploits/headers.adoc
  26. 37 2
      docs/modules/ROOT/pages/reactive/exploits/headers.adoc
  27. 1 14
      docs/modules/ROOT/pages/servlet/appendix/namespace/http.adoc
  28. 6 5
      docs/modules/ROOT/pages/servlet/exploits/headers.adoc
  29. 2 50
      web/src/main/java/org/springframework/security/web/header/writers/XXssProtectionHeaderWriter.java
  30. 3 52
      web/src/main/java/org/springframework/security/web/server/header/XXssProtectionServerHttpHeadersWriter.java
  31. 1 32
      web/src/test/java/org/springframework/security/web/header/writers/XXssProtectionHeaderWriterTests.java
  32. 0 17
      web/src/test/java/org/springframework/security/web/server/header/XXssProtectionServerHttpHeadersWriterTests.java

+ 2 - 45
config/src/main/java/org/springframework/security/config/annotation/web/configurers/HeadersConfigurer.java

@@ -64,7 +64,7 @@ import org.springframework.util.Assert;
  * 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
  * </pre>
  *
  * @author Rob Winch
@@ -73,6 +73,7 @@ import org.springframework.util.Assert;
  * @author Eddú Meléndez
  * @author Vedran Pavic
  * @author Ankur Pathak
+ * @author Daniel Garnier-Moiroux
  * @since 3.2
  */
 public class HeadersConfigurer<H extends HttpSecurityBuilder<H>>
@@ -733,50 +734,6 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>>
 			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:
-		 *
-		 * <pre>
-		 * X-XSS-Protection: 1
-		 * </pre>
-		 *
-		 * or if {@link XXssProtectionHeaderWriter#setBlock(boolean)} of the given
-		 * {@link XXssProtectionHeaderWriter} is true
-		 *
-		 *
-		 * <pre>
-		 * X-XSS-Protection: 1; mode=block
-		 * </pre>
-		 *
-		 * If false, will explicitly disable specify that X-XSS-Protection is disabled.
-		 * For example:
-		 *
-		 * <pre>
-		 * X-XSS-Protection: 0
-		 * </pre>
-		 * @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}.

+ 0 - 18
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 @@ public class HeadersBeanDefinitionParser implements BeanDefinitionParser {
 		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) {

+ 2 - 2
config/src/main/java/org/springframework/security/config/web/server/ServerHttpSecurity.java

@@ -1040,7 +1040,7 @@ public class ServerHttpSecurity {
 	 * 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
 	 * </pre>
 	 *
 	 * such that "Strict-Transport-Security" is only added on secure requests.
@@ -1081,7 +1081,7 @@ public class ServerHttpSecurity {
 	 * 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
 	 * </pre>
 	 *
 	 * such that "Strict-Transport-Security" is only added on secure requests.

+ 1 - 9
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<HttpSecurity>.XXssConfig) -> Unit {
         return { xssProtection ->
-            block?.also { xssProtection.block(block!!) }
-            xssProtectionEnabled?.also { xssProtection.xssProtectionEnabled(xssProtectionEnabled!!) }
             headerValue?.also { xssProtection.headerValue(headerValue) }
 
             if (disabled) {

+ 1 - 7
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 =

+ 1 - 15
config/src/main/resources/org/springframework/security/config/spring-security-6.0.xsd

@@ -3553,23 +3553,9 @@
                 </xs:documentation>
          </xs:annotation>
       </xs:attribute>
-      <xs:attribute name="enabled" type="xs:boolean">
-         <xs:annotation>
-            <xs:documentation>specify that XSS Protection should be explicitly enabled or disabled. Default is 'true'
-                meaning it is enabled.
-                </xs:documentation>
-         </xs:annotation>
-      </xs:attribute>
-      <xs:attribute name="block" type="xs:boolean">
-         <xs:annotation>
-            <xs:documentation>Add mode=block to the header or not, default is on.
-                </xs:documentation>
-         </xs:annotation>
-      </xs:attribute>
       <xs:attribute name="header-value">
          <xs:annotation>
-            <xs:documentation>Specify the value for the X-Xss-Protection header. When set, overrides both enabled and
-                block attributes.
+            <xs:documentation>Specify the value for the X-Xss-Protection header. Defaults to "0".
                 </xs:documentation>
          </xs:annotation>
          <xs:simpleType>

+ 1 - 1
config/src/test/java/org/springframework/security/config/annotation/web/configuration/HttpSecurityConfigurationTests.java

@@ -122,7 +122,7 @@ public class HttpSecurityConfigurationTests {
 				.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(

+ 1 - 1
config/src/test/java/org/springframework/security/config/annotation/web/configurers/HeadersConfigurerEagerHeadersTests.java

@@ -57,7 +57,7 @@ public class HeadersConfigurerEagerHeadersTests {
 				.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

+ 14 - 14
config/src/test/java/org/springframework/security/config/annotation/web/configurers/HeadersConfigurerTests.java

@@ -80,7 +80,7 @@ public class HeadersConfigurerTests {
 				.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 class HeadersConfigurerTests {
 				.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 class HeadersConfigurerTests {
 			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 class HeadersConfigurerTests {
 	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 @@ public class HeadersConfigurerTests {
 
 	@Configuration
 	@EnableWebSecurity
-	static class XssProtectionValueDisabledConfig {
+	static class XssProtectionValueEnabledModeBlockConfig {
 
 		@Bean
 		SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
@@ -728,7 +728,7 @@ public class HeadersConfigurerTests {
 				.headers()
 					.defaultsDisabled()
 					.xssProtection()
-					.headerValue(XXssProtectionHeaderWriter.HeaderValue.DISABLED);
+					.headerValue(XXssProtectionHeaderWriter.HeaderValue.ENABLED_MODE_BLOCK);
 			// @formatter:on
 			return http.build();
 		}
@@ -755,7 +755,7 @@ public class HeadersConfigurerTests {
 
 	@Configuration
 	@EnableWebSecurity
-	static class XssProtectionValueDisabledInLambdaConfig {
+	static class XssProtectionValueEnabledModeBlockInLambdaConfig {
 
 		@Bean
 		SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
@@ -765,7 +765,7 @@ public class HeadersConfigurerTests {
 					headers
 						.defaultsDisabled()
 						.xssProtection((xXssConfig) ->
-							xXssConfig.headerValue(XXssProtectionHeaderWriter.HeaderValue.DISABLED)
+							xXssConfig.headerValue(XXssProtectionHeaderWriter.HeaderValue.ENABLED_MODE_BLOCK)
 						)
 				);
 			// @formatter:on

+ 3 - 3
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 class NamespaceHttpHeadersTests {
 	@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 @@ public class NamespaceHttpHeadersTests {
 					// xss-protection@enabled and xss-protection@block
 					.defaultsDisabled()
 					.xssProtection()
-						.headerValue(XXssProtectionHeaderWriter.HeaderValue.ENABLED);
+						.headerValue(XXssProtectionHeaderWriter.HeaderValue.ENABLED_MODE_BLOCK);
 			// @formatter:on
 			return http.build();
 		}

+ 1 - 69
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 class HttpHeadersConfigTests {
 		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<String> 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<String> 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 class HttpHeadersConfigTests {
 		// @formatter:on
 	}
 
-	@Test
-	public void requestWhenSettingXssProtectionDisabledHeaderValueToOneThenDefaultsToOne() throws Exception {
-		Set<String> 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<String, String> includedHeaders = ImmutableMap.<String, String>builder()
@@ -693,21 +640,6 @@ public class HttpHeadersConfigTests {
 				.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(

+ 1 - 1
config/src/test/java/org/springframework/security/config/web/server/HeaderSpecTests.java

@@ -75,7 +75,7 @@ public class HeaderSpecTests {
 		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

+ 1 - 1
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") }
         }
     }
 

+ 1 - 1
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")
             }
         }
     }

+ 17 - 44
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
                     }
                 }
             }

+ 1 - 1
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

+ 1 - 1
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

+ 3 - 3
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
                     }
                 }
             }

+ 0 - 37
config/src/test/resources/org/springframework/security/config/http/HttpHeadersConfigTests-DefaultsDisabledWithXssProtectionDisabled.xml

@@ -1,37 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-  ~ Copyright 2002-2018 the original author or authors.
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      https://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-  -->
-
-<b:beans xmlns:b="http://www.springframework.org/schema/beans"
-		xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-		xmlns="http://www.springframework.org/schema/security"
-		xsi:schemaLocation="
-			http://www.springframework.org/schema/security
-			https://www.springframework.org/schema/security/spring-security.xsd
-			http://www.springframework.org/schema/beans
-			https://www.springframework.org/schema/beans/spring-beans.xsd">
-
-	<http auto-config="true">
-		<headers defaults-disabled="true">
-			<xss-protection enabled="false"/>
-		</headers>
-		<intercept-url pattern="/**" access="permitAll"/>
-	</http>
-
-	<b:bean name="simple" class="org.springframework.security.config.http.HttpHeadersConfigTests.SimpleController"/>
-
-	<b:import resource="userservice.xml"/>
-</b:beans>

+ 0 - 37
config/src/test/resources/org/springframework/security/config/http/HttpHeadersConfigTests-DefaultsDisabledWithXssProtectionDisabledAndBlockSet.xml

@@ -1,37 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-  ~ Copyright 2002-2018 the original author or authors.
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      https://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-  -->
-
-<b:beans xmlns:b="http://www.springframework.org/schema/beans"
-		xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-		xmlns="http://www.springframework.org/schema/security"
-		xsi:schemaLocation="
-			http://www.springframework.org/schema/security
-			https://www.springframework.org/schema/security/spring-security.xsd
-			http://www.springframework.org/schema/beans
-			https://www.springframework.org/schema/beans/spring-beans.xsd">
-
-	<http auto-config="true">
-		<headers defaults-disabled="true">
-			<xss-protection enabled="false" block="true"/>
-		</headers>
-		<intercept-url pattern="/**" access="permitAll"/>
-	</http>
-
-	<b:bean name="simple" class="org.springframework.security.config.http.HttpHeadersConfigTests.SimpleController"/>
-
-	<b:import resource="userservice.xml"/>
-</b:beans>

+ 0 - 37
config/src/test/resources/org/springframework/security/config/http/HttpHeadersConfigTests-DefaultsDisabledWithXssProtectionDisabledAndHeaderValueOne.xml

@@ -1,37 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-  ~ Copyright 2002-2022 the original author or authors.
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      https://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-  -->
-
-<b:beans xmlns:b="http://www.springframework.org/schema/beans"
-		xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-		xmlns="http://www.springframework.org/schema/security"
-		xsi:schemaLocation="
-			http://www.springframework.org/schema/security
-			https://www.springframework.org/schema/security/spring-security.xsd
-			http://www.springframework.org/schema/beans
-			https://www.springframework.org/schema/beans/spring-beans.xsd">
-
-	<http auto-config="true">
-		<headers defaults-disabled="true">
-			<xss-protection enabled="false" header-value="1"/>
-		</headers>
-		<intercept-url pattern="/**" access="permitAll"/>
-	</http>
-
-	<b:bean name="simple" class="org.springframework.security.config.http.HttpHeadersConfigTests.SimpleController"/>
-
-	<b:import resource="userservice.xml"/>
-</b:beans>

+ 0 - 37
config/src/test/resources/org/springframework/security/config/http/HttpHeadersConfigTests-DefaultsDisabledWithXssProtectionEnabled.xml

@@ -1,37 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-  ~ Copyright 2002-2018 the original author or authors.
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      https://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-  -->
-
-<b:beans xmlns:b="http://www.springframework.org/schema/beans"
-		xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-		xmlns="http://www.springframework.org/schema/security"
-		xsi:schemaLocation="
-			http://www.springframework.org/schema/security
-			https://www.springframework.org/schema/security/spring-security.xsd
-			http://www.springframework.org/schema/beans
-			https://www.springframework.org/schema/beans/spring-beans.xsd">
-
-	<http auto-config="true">
-		<headers defaults-disabled="true">
-			<xss-protection enabled="true"/>
-		</headers>
-		<intercept-url pattern="/**" access="permitAll"/>
-	</http>
-
-	<b:bean name="simple" class="org.springframework.security.config.http.HttpHeadersConfigTests.SimpleController"/>
-
-	<b:import resource="userservice.xml"/>
-</b:beans>

+ 0 - 37
config/src/test/resources/org/springframework/security/config/http/HttpHeadersConfigTests-XssProtectionDisabledAndEnabled.xml

@@ -1,37 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-  ~ Copyright 2002-2018 the original author or authors.
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      https://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-  -->
-
-<b:beans xmlns:b="http://www.springframework.org/schema/beans"
-		xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-		xmlns="http://www.springframework.org/schema/security"
-		xsi:schemaLocation="
-			http://www.springframework.org/schema/security
-			https://www.springframework.org/schema/security/spring-security.xsd
-			http://www.springframework.org/schema/beans
-			https://www.springframework.org/schema/beans/spring-beans.xsd">
-
-	<http auto-config="true">
-		<headers>
-			<xss-protection disabled="true" enabled="true"/>
-		</headers>
-		<intercept-url pattern="/**" access="permitAll"/>
-	</http>
-
-	<b:bean name="simple" class="org.springframework.security.config.http.HttpHeadersConfigTests.SimpleController"/>
-
-	<b:import resource="userservice.xml"/>
-</b:beans>

+ 0 - 37
config/src/test/resources/org/springframework/security/config/http/HttpHeadersConfigTests-XssProtectionDisabledSpecifyingBlock.xml

@@ -1,37 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-  ~ Copyright 2002-2018 the original author or authors.
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      https://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-  -->
-
-<b:beans xmlns:b="http://www.springframework.org/schema/beans"
-		xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-		xmlns="http://www.springframework.org/schema/security"
-		xsi:schemaLocation="
-			http://www.springframework.org/schema/security
-			https://www.springframework.org/schema/security/spring-security.xsd
-			http://www.springframework.org/schema/beans
-			https://www.springframework.org/schema/beans/spring-beans.xsd">
-
-	<http auto-config="true">
-		<headers>
-			<xss-protection disabled="true" block="true"/>
-		</headers>
-		<intercept-url pattern="/**" access="permitAll"/>
-	</http>
-
-	<b:bean name="simple" class="org.springframework.security.config.http.HttpHeadersConfigTests.SimpleController"/>
-
-	<b:import resource="userservice.xml"/>
-</b:beans>

+ 3 - 7
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
 ----
 ====
 

+ 37 - 2
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 <<headers-xss-protection,X-XSS-Protection header>.
-You can disable `X-XSS-Protection`:
+By default, Spring Security instructs browsers to disable the XSS Auditor by using <<headers-xss-protection,X-XSS-Protection header>.
+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.

+ 1 - 14
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]]

+ 6 - 5
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 <<headers-xss-protection,X-XSS-Protection header>.
+By default, Spring Security instructs browsers to disable the XSS Auditor by using <<headers-xss-protection,X-XSS-Protection header>.
 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 {
 	<!-- ... -->
 
 	<headers>
-		<xss-protection block="false"/>
+		<xss-protection headerValue="1; mode=block"/>
 	</headers>
 </http>
 ----
@@ -581,7 +582,7 @@ class SecurityConfig {
         http {
             headers {
                 xssProtection {
-                    block = false
+                    headerValue = XXssProtectionHeaderWriter.HeaderValue.ENABLED_MODE_BLOCK
                 }
             }
         }

+ 2 - 50
web/src/main/java/org/springframework/security/web/header/writers/XXssProtectionHeaderWriter.java

@@ -29,6 +29,7 @@ import org.springframework.util.Assert;
  *
  * @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 final class XXssProtectionHeaderWriter implements HeaderWriter {
 		}
 	}
 
-	/**
-	 * If true, will contain a value of 1. For example:
-	 *
-	 * <pre>
-	 * X-XSS-Protection: 1
-	 * </pre>
-	 *
-	 * or if {@link #setBlock(boolean)} is true
-	 *
-	 *
-	 * <pre>
-	 * X-XSS-Protection: 1; mode=block
-	 * </pre>
-	 *
-	 * If false, will explicitly disable specify that X-XSS-Protection is disabled. For
-	 * example:
-	 *
-	 * <pre>
-	 * X-XSS-Protection: 0
-	 * </pre>
-	 * @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.
 	 * <p>

+ 3 - 52
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 class XXssProtectionServerHttpHeadersWriter implements ServerHttpHeadersW
 	}
 
 	/**
-	 * If true, will contain a value of 1. For example:
-	 *
-	 * <pre>
-	 * X-XSS-Protection: 1
-	 * </pre>
-	 *
-	 * or if {@link #setBlock(boolean)} is true
-	 *
-	 *
-	 * <pre>
-	 * X-XSS-Protection: 1; mode=block
-	 * </pre>
-	 *
-	 * If false, will explicitly disable specify that X-XSS-Protection is disabled. For
-	 * example:
-	 *
-	 * <pre>
-	 * X-XSS-Protection: 0
-	 * </pre>
-	 * @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}
 	 * <p>
 	 * If {@link HeaderValue#DISABLED}, will specify that X-XSS-Protection is disabled.
 	 * For example:

+ 1 - 32
web/src/test/java/org/springframework/security/web/header/writers/XXssProtectionHeaderWriterTests.java

@@ -28,6 +28,7 @@ import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException
 /**
  * @author Rob Winch
  * @author Ankur Pathak
+ * @author Daniel Garnier-Moiroux
  *
  */
 public class XXssProtectionHeaderWriterTests {
@@ -49,43 +50,11 @@ public class XXssProtectionHeaderWriterTests {
 
 	@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");

+ 0 - 17
web/src/test/java/org/springframework/security/web/server/header/XXssProtectionServerHttpHeadersWriterTests.java

@@ -46,23 +46,6 @@ public class XXssProtectionServerHttpHeadersWriterTests {
 
 	@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");