Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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
* </pre>
*
* @author Rob Winch
Expand All @@ -73,6 +73,7 @@
* @author Eddú Meléndez
* @author Vedran Pavic
* @author Ankur Pathak
* @author Daniel Garnier-Moiroux
* @since 3.2
*/
public class HeadersConfigurer<H extends HttpSecurityBuilder<H>>
Expand Down Expand Up @@ -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:
*
* <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}.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down Expand Up @@ -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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1038,7 +1038,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
* </pre>
*
* such that "Strict-Transport-Security" is only added on secure requests.
Expand Down Expand Up @@ -1079,7 +1079,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
* </pre>
*
* such that "Strict-Transport-Security" is only added on secure requests.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1265,13 +1265,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 =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3546,23 +3546,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>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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);
Expand Down Expand Up @@ -169,33 +169,33 @@ 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);
}

@Test
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);
}

Expand Down Expand Up @@ -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 {
Expand All @@ -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();
}
Expand All @@ -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 {
Expand All @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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();
}
Expand Down
Loading