mirror of
https://github.com/spring-projects/spring-security.git
synced 2025-03-09 06:50:05 +00:00
Default X-Xss-Protection header value to "0"
Closes gh-9631
This commit is contained in:
parent
dcda899c8c
commit
27059ced87
@ -64,7 +64,7 @@ import org.springframework.util.Assert;
|
|||||||
* X-Content-Type-Options: nosniff
|
* X-Content-Type-Options: nosniff
|
||||||
* Strict-Transport-Security: max-age=31536000 ; includeSubDomains
|
* Strict-Transport-Security: max-age=31536000 ; includeSubDomains
|
||||||
* X-Frame-Options: DENY
|
* X-Frame-Options: DENY
|
||||||
* X-XSS-Protection: 1; mode=block
|
* X-XSS-Protection: 0
|
||||||
* </pre>
|
* </pre>
|
||||||
*
|
*
|
||||||
* @author Rob Winch
|
* @author Rob Winch
|
||||||
@ -73,6 +73,7 @@ import org.springframework.util.Assert;
|
|||||||
* @author Eddú Meléndez
|
* @author Eddú Meléndez
|
||||||
* @author Vedran Pavic
|
* @author Vedran Pavic
|
||||||
* @author Ankur Pathak
|
* @author Ankur Pathak
|
||||||
|
* @author Daniel Garnier-Moiroux
|
||||||
* @since 3.2
|
* @since 3.2
|
||||||
*/
|
*/
|
||||||
public class HeadersConfigurer<H extends HttpSecurityBuilder<H>>
|
public class HeadersConfigurer<H extends HttpSecurityBuilder<H>>
|
||||||
@ -733,50 +734,6 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>>
|
|||||||
enable();
|
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
|
* Sets the value of the X-XSS-PROTECTION header. OWASP recommends using
|
||||||
* {@link XXssProtectionHeaderWriter.HeaderValue#DISABLED}.
|
* {@link XXssProtectionHeaderWriter.HeaderValue#DISABLED}.
|
||||||
|
@ -69,10 +69,6 @@ public class HeadersBeanDefinitionParser implements BeanDefinitionParser {
|
|||||||
|
|
||||||
private static final String ATT_DISABLED = "disabled";
|
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_POLICY = "policy";
|
||||||
|
|
||||||
private static final String ATT_STRATEGY = "strategy";
|
private static final String ATT_STRATEGY = "strategy";
|
||||||
@ -583,20 +579,6 @@ public class HeadersBeanDefinitionParser implements BeanDefinitionParser {
|
|||||||
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(XXssProtectionHeaderWriter.class);
|
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(XXssProtectionHeaderWriter.class);
|
||||||
if (xssElt != null) {
|
if (xssElt != null) {
|
||||||
boolean disabled = "true".equals(getAttribute(xssElt, ATT_DISABLED, "false"));
|
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
|
XXssProtectionHeaderWriter.HeaderValue headerValue = XXssProtectionHeaderWriter.HeaderValue
|
||||||
.from(xssElt.getAttribute(ATT_HEADER_VALUE));
|
.from(xssElt.getAttribute(ATT_HEADER_VALUE));
|
||||||
if (headerValue != null) {
|
if (headerValue != null) {
|
||||||
|
@ -1040,7 +1040,7 @@ public class ServerHttpSecurity {
|
|||||||
* X-Content-Type-Options: nosniff
|
* X-Content-Type-Options: nosniff
|
||||||
* Strict-Transport-Security: max-age=31536000 ; includeSubDomains
|
* Strict-Transport-Security: max-age=31536000 ; includeSubDomains
|
||||||
* X-Frame-Options: DENY
|
* X-Frame-Options: DENY
|
||||||
* X-XSS-Protection: 1; mode=block
|
* X-XSS-Protection: 0
|
||||||
* </pre>
|
* </pre>
|
||||||
*
|
*
|
||||||
* such that "Strict-Transport-Security" is only added on secure requests.
|
* such that "Strict-Transport-Security" is only added on secure requests.
|
||||||
@ -1081,7 +1081,7 @@ public class ServerHttpSecurity {
|
|||||||
* X-Content-Type-Options: nosniff
|
* X-Content-Type-Options: nosniff
|
||||||
* Strict-Transport-Security: max-age=31536000 ; includeSubDomains
|
* Strict-Transport-Security: max-age=31536000 ; includeSubDomains
|
||||||
* X-Frame-Options: DENY
|
* X-Frame-Options: DENY
|
||||||
* X-XSS-Protection: 1; mode=block
|
* X-XSS-Protection: 0
|
||||||
* </pre>
|
* </pre>
|
||||||
*
|
*
|
||||||
* such that "Strict-Transport-Security" is only added on secure requests.
|
* such that "Strict-Transport-Security" is only added on secure requests.
|
||||||
|
@ -25,18 +25,12 @@ import org.springframework.security.web.header.writers.XXssProtectionHeaderWrite
|
|||||||
* idiomatic Kotlin code.
|
* idiomatic Kotlin code.
|
||||||
*
|
*
|
||||||
* @author Eleftheria Stein
|
* @author Eleftheria Stein
|
||||||
|
* @author Daniel Garnier-Moiroux
|
||||||
* @since 5.3
|
* @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].
|
* @property headerValue the value of the X-XSS-Protection header. OWASP recommends [HeaderValue.DISABLED].
|
||||||
*/
|
*/
|
||||||
@HeadersSecurityMarker
|
@HeadersSecurityMarker
|
||||||
class XssProtectionConfigDsl {
|
class XssProtectionConfigDsl {
|
||||||
@Deprecated("use headerValue instead")
|
|
||||||
var block: Boolean? = null
|
|
||||||
@Deprecated("use headerValue instead")
|
|
||||||
var xssProtectionEnabled: Boolean? = null
|
|
||||||
var headerValue: HeaderValue? = null
|
var headerValue: HeaderValue? = null
|
||||||
|
|
||||||
private var disabled = false
|
private var disabled = false
|
||||||
@ -50,8 +44,6 @@ class XssProtectionConfigDsl {
|
|||||||
|
|
||||||
internal fun get(): (HeadersConfigurer<HttpSecurity>.XXssConfig) -> Unit {
|
internal fun get(): (HeadersConfigurer<HttpSecurity>.XXssConfig) -> Unit {
|
||||||
return { xssProtection ->
|
return { xssProtection ->
|
||||||
block?.also { xssProtection.block(block!!) }
|
|
||||||
xssProtectionEnabled?.also { xssProtection.xssProtectionEnabled(xssProtectionEnabled!!) }
|
|
||||||
headerValue?.also { xssProtection.headerValue(headerValue) }
|
headerValue?.also { xssProtection.headerValue(headerValue) }
|
||||||
|
|
||||||
if (disabled) {
|
if (disabled) {
|
||||||
|
@ -1268,13 +1268,7 @@ xss-protection.attlist &=
|
|||||||
## disable the X-XSS-Protection header. Default is 'false' meaning it is enabled.
|
## disable the X-XSS-Protection header. Default is 'false' meaning it is enabled.
|
||||||
attribute disabled {xsd:boolean}?
|
attribute disabled {xsd:boolean}?
|
||||||
xss-protection.attlist &=
|
xss-protection.attlist &=
|
||||||
## specify that XSS Protection should be explicitly enabled or disabled. Default is 'true' meaning it is enabled.
|
## Specify the value for the X-Xss-Protection header. Defaults to "0".
|
||||||
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.
|
|
||||||
attribute header-value {"0"|"1"|"1; mode=block"}?
|
attribute header-value {"0"|"1"|"1; mode=block"}?
|
||||||
|
|
||||||
content-type-options =
|
content-type-options =
|
||||||
|
@ -3553,23 +3553,9 @@
|
|||||||
</xs:documentation>
|
</xs:documentation>
|
||||||
</xs:annotation>
|
</xs:annotation>
|
||||||
</xs:attribute>
|
</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:attribute name="header-value">
|
||||||
<xs:annotation>
|
<xs:annotation>
|
||||||
<xs:documentation>Specify the value for the X-Xss-Protection header. When set, overrides both enabled and
|
<xs:documentation>Specify the value for the X-Xss-Protection header. Defaults to "0".
|
||||||
block attributes.
|
|
||||||
</xs:documentation>
|
</xs:documentation>
|
||||||
</xs:annotation>
|
</xs:annotation>
|
||||||
<xs:simpleType>
|
<xs:simpleType>
|
||||||
|
@ -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.CACHE_CONTROL, "no-cache, no-store, max-age=0, must-revalidate"))
|
||||||
.andExpect(header().string(HttpHeaders.EXPIRES, "0"))
|
.andExpect(header().string(HttpHeaders.EXPIRES, "0"))
|
||||||
.andExpect(header().string(HttpHeaders.PRAGMA, "no-cache"))
|
.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();
|
.andReturn();
|
||||||
// @formatter:on
|
// @formatter:on
|
||||||
assertThat(mvcResult.getResponse().getHeaderNames()).containsExactlyInAnyOrder(
|
assertThat(mvcResult.getResponse().getHeaderNames()).containsExactlyInAnyOrder(
|
||||||
|
@ -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.CACHE_CONTROL, "no-cache, no-store, max-age=0, must-revalidate"))
|
||||||
.andExpect(header().string(HttpHeaders.EXPIRES, "0"))
|
.andExpect(header().string(HttpHeaders.EXPIRES, "0"))
|
||||||
.andExpect(header().string(HttpHeaders.PRAGMA, "no-cache"))
|
.andExpect(header().string(HttpHeaders.PRAGMA, "no-cache"))
|
||||||
.andExpect(header().string("X-XSS-Protection", "1; mode=block"));
|
.andExpect(header().string("X-XSS-Protection", "0"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
|
@ -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.CACHE_CONTROL, "no-cache, no-store, max-age=0, must-revalidate"))
|
||||||
.andExpect(header().string(HttpHeaders.EXPIRES, "0"))
|
.andExpect(header().string(HttpHeaders.EXPIRES, "0"))
|
||||||
.andExpect(header().string(HttpHeaders.PRAGMA, "no-cache"))
|
.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(
|
assertThat(mvcResult.getResponse().getHeaderNames()).containsExactlyInAnyOrder(
|
||||||
HttpHeaders.X_CONTENT_TYPE_OPTIONS, HttpHeaders.X_FRAME_OPTIONS, HttpHeaders.STRICT_TRANSPORT_SECURITY,
|
HttpHeaders.X_CONTENT_TYPE_OPTIONS, HttpHeaders.X_FRAME_OPTIONS, HttpHeaders.STRICT_TRANSPORT_SECURITY,
|
||||||
HttpHeaders.CACHE_CONTROL, HttpHeaders.EXPIRES, HttpHeaders.PRAGMA, HttpHeaders.X_XSS_PROTECTION);
|
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.CACHE_CONTROL, "no-cache, no-store, max-age=0, must-revalidate"))
|
||||||
.andExpect(header().string(HttpHeaders.EXPIRES, "0"))
|
.andExpect(header().string(HttpHeaders.EXPIRES, "0"))
|
||||||
.andExpect(header().string(HttpHeaders.PRAGMA, "no-cache"))
|
.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(
|
assertThat(mvcResult.getResponse().getHeaderNames()).containsExactlyInAnyOrder(
|
||||||
HttpHeaders.X_CONTENT_TYPE_OPTIONS, HttpHeaders.X_FRAME_OPTIONS, HttpHeaders.STRICT_TRANSPORT_SECURITY,
|
HttpHeaders.X_CONTENT_TYPE_OPTIONS, HttpHeaders.X_FRAME_OPTIONS, HttpHeaders.STRICT_TRANSPORT_SECURITY,
|
||||||
HttpHeaders.CACHE_CONTROL, HttpHeaders.EXPIRES, HttpHeaders.PRAGMA, HttpHeaders.X_XSS_PROTECTION);
|
HttpHeaders.CACHE_CONTROL, HttpHeaders.EXPIRES, HttpHeaders.PRAGMA, HttpHeaders.X_XSS_PROTECTION);
|
||||||
@ -169,16 +169,16 @@ public class HeadersConfigurerTests {
|
|||||||
throws Exception {
|
throws Exception {
|
||||||
this.spring.register(XssProtectionConfig.class).autowire();
|
this.spring.register(XssProtectionConfig.class).autowire();
|
||||||
MvcResult mvcResult = this.mvc.perform(get("/").secure(true))
|
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);
|
assertThat(mvcResult.getResponse().getHeaderNames()).containsExactly(HttpHeaders.X_XSS_PROTECTION);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getWhenHeaderDefaultsDisabledAndXssProtectionConfiguredValueDisabledThenOnlyXssProtectionHeaderInResponse()
|
public void getWhenHeaderDefaultsDisabledAndXssProtectionConfiguredEnabledModeBlockThenOnlyXssProtectionHeaderInResponse()
|
||||||
throws Exception {
|
throws Exception {
|
||||||
this.spring.register(XssProtectionValueDisabledConfig.class).autowire();
|
this.spring.register(XssProtectionValueEnabledModeBlockConfig.class).autowire();
|
||||||
MvcResult mvcResult = this.mvc.perform(get("/").secure(true))
|
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);
|
assertThat(mvcResult.getResponse().getHeaderNames()).containsExactly(HttpHeaders.X_XSS_PROTECTION);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -186,16 +186,16 @@ public class HeadersConfigurerTests {
|
|||||||
public void getWhenOnlyXssProtectionConfiguredInLambdaThenOnlyXssProtectionHeaderInResponse() throws Exception {
|
public void getWhenOnlyXssProtectionConfiguredInLambdaThenOnlyXssProtectionHeaderInResponse() throws Exception {
|
||||||
this.spring.register(XssProtectionInLambdaConfig.class).autowire();
|
this.spring.register(XssProtectionInLambdaConfig.class).autowire();
|
||||||
MvcResult mvcResult = this.mvc.perform(get("/").secure(true))
|
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);
|
assertThat(mvcResult.getResponse().getHeaderNames()).containsExactly(HttpHeaders.X_XSS_PROTECTION);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getWhenHeaderDefaultsDisabledAndXssProtectionConfiguredValueDisabledInLambdaThenOnlyXssProtectionHeaderInResponse()
|
public void getWhenHeaderDefaultsDisabledAndXssProtectionConfiguredValueEnabledModeBlockInLambdaThenOnlyXssProtectionHeaderInResponse()
|
||||||
throws Exception {
|
throws Exception {
|
||||||
this.spring.register(XssProtectionValueDisabledInLambdaConfig.class).autowire();
|
this.spring.register(XssProtectionValueEnabledModeBlockInLambdaConfig.class).autowire();
|
||||||
MvcResult mvcResult = this.mvc.perform(get("/").secure(true))
|
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);
|
assertThat(mvcResult.getResponse().getHeaderNames()).containsExactly(HttpHeaders.X_XSS_PROTECTION);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -719,7 +719,7 @@ public class HeadersConfigurerTests {
|
|||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
@EnableWebSecurity
|
@EnableWebSecurity
|
||||||
static class XssProtectionValueDisabledConfig {
|
static class XssProtectionValueEnabledModeBlockConfig {
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
||||||
@ -728,7 +728,7 @@ public class HeadersConfigurerTests {
|
|||||||
.headers()
|
.headers()
|
||||||
.defaultsDisabled()
|
.defaultsDisabled()
|
||||||
.xssProtection()
|
.xssProtection()
|
||||||
.headerValue(XXssProtectionHeaderWriter.HeaderValue.DISABLED);
|
.headerValue(XXssProtectionHeaderWriter.HeaderValue.ENABLED_MODE_BLOCK);
|
||||||
// @formatter:on
|
// @formatter:on
|
||||||
return http.build();
|
return http.build();
|
||||||
}
|
}
|
||||||
@ -755,7 +755,7 @@ public class HeadersConfigurerTests {
|
|||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
@EnableWebSecurity
|
@EnableWebSecurity
|
||||||
static class XssProtectionValueDisabledInLambdaConfig {
|
static class XssProtectionValueEnabledModeBlockInLambdaConfig {
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
||||||
@ -765,7 +765,7 @@ public class HeadersConfigurerTests {
|
|||||||
headers
|
headers
|
||||||
.defaultsDisabled()
|
.defaultsDisabled()
|
||||||
.xssProtection((xXssConfig) ->
|
.xssProtection((xXssConfig) ->
|
||||||
xXssConfig.headerValue(XXssProtectionHeaderWriter.HeaderValue.DISABLED)
|
xXssConfig.headerValue(XXssProtectionHeaderWriter.HeaderValue.ENABLED_MODE_BLOCK)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
// @formatter:on
|
// @formatter:on
|
||||||
|
@ -62,7 +62,7 @@ public class NamespaceHttpHeadersTests {
|
|||||||
defaultHeaders.put("Cache-Control", "no-cache, no-store, max-age=0, must-revalidate");
|
defaultHeaders.put("Cache-Control", "no-cache, no-store, max-age=0, must-revalidate");
|
||||||
defaultHeaders.put("Expires", "0");
|
defaultHeaders.put("Expires", "0");
|
||||||
defaultHeaders.put("Pragma", "no-cache");
|
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);
|
public final SpringTestContext spring = new SpringTestContext(this);
|
||||||
|
|
||||||
@ -116,7 +116,7 @@ public class NamespaceHttpHeadersTests {
|
|||||||
@Test
|
@Test
|
||||||
public void requestWhenXssCustomThenBehaviorMatchesNamespace() throws Exception {
|
public void requestWhenXssCustomThenBehaviorMatchesNamespace() throws Exception {
|
||||||
this.spring.register(XssProtectionCustomConfig.class).autowire();
|
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
|
@Test
|
||||||
@ -291,7 +291,7 @@ public class NamespaceHttpHeadersTests {
|
|||||||
// xss-protection@enabled and xss-protection@block
|
// xss-protection@enabled and xss-protection@block
|
||||||
.defaultsDisabled()
|
.defaultsDisabled()
|
||||||
.xssProtection()
|
.xssProtection()
|
||||||
.headerValue(XXssProtectionHeaderWriter.HeaderValue.ENABLED);
|
.headerValue(XXssProtectionHeaderWriter.HeaderValue.ENABLED_MODE_BLOCK);
|
||||||
// @formatter:on
|
// @formatter:on
|
||||||
return http.build();
|
return http.build();
|
||||||
}
|
}
|
||||||
|
@ -62,7 +62,7 @@ public class HttpHeadersConfigTests {
|
|||||||
.put("Cache-Control", "no-cache, no-store, max-age=0, must-revalidate")
|
.put("Cache-Control", "no-cache, no-store, max-age=0, must-revalidate")
|
||||||
.put("Expires", "0")
|
.put("Expires", "0")
|
||||||
.put("Pragma", "no-cache")
|
.put("Pragma", "no-cache")
|
||||||
.put("X-XSS-Protection", "1; mode=block")
|
.put("X-XSS-Protection", "0")
|
||||||
.build();
|
.build();
|
||||||
// @formatter:on
|
// @formatter:on
|
||||||
|
|
||||||
@ -351,32 +351,6 @@ public class HttpHeadersConfigTests {
|
|||||||
excludedHeaders.remove("X-XSS-Protection");
|
excludedHeaders.remove("X-XSS-Protection");
|
||||||
this.spring.configLocations(this.xml("DefaultsDisabledWithXssProtection")).autowire();
|
this.spring.configLocations(this.xml("DefaultsDisabledWithXssProtection")).autowire();
|
||||||
// @formatter:off
|
// @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("/"))
|
this.mvc.perform(get("/"))
|
||||||
.andExpect(status().isOk())
|
.andExpect(status().isOk())
|
||||||
.andExpect(header().string("X-XSS-Protection", "0"))
|
.andExpect(header().string("X-XSS-Protection", "0"))
|
||||||
@ -423,33 +397,6 @@ public class HttpHeadersConfigTests {
|
|||||||
// @formatter:on
|
// @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
|
@Test
|
||||||
public void requestWhenUsingCacheControlThenRespondsWithCorrespondingHeaders() throws Exception {
|
public void requestWhenUsingCacheControlThenRespondsWithCorrespondingHeaders() throws Exception {
|
||||||
Map<String, String> includedHeaders = ImmutableMap.<String, String>builder()
|
Map<String, String> includedHeaders = ImmutableMap.<String, String>builder()
|
||||||
@ -693,21 +640,6 @@ public class HttpHeadersConfigTests {
|
|||||||
.withMessageContaining("request-matcher-ref");
|
.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
|
@Test
|
||||||
public void configureWhenXssProtectionDisabledAndHeaderValueSpecifiedThenAutowireFails() {
|
public void configureWhenXssProtectionDisabledAndHeaderValueSpecifiedThenAutowireFails() {
|
||||||
assertThatExceptionOfType(BeanDefinitionParsingException.class).isThrownBy(
|
assertThatExceptionOfType(BeanDefinitionParsingException.class).isThrownBy(
|
||||||
|
@ -75,7 +75,7 @@ public class HeaderSpecTests {
|
|||||||
this.expectedHeaders.add(HttpHeaders.EXPIRES, "0");
|
this.expectedHeaders.add(HttpHeaders.EXPIRES, "0");
|
||||||
this.expectedHeaders.add(ContentTypeOptionsServerHttpHeadersWriter.X_CONTENT_OPTIONS, "nosniff");
|
this.expectedHeaders.add(ContentTypeOptionsServerHttpHeadersWriter.X_CONTENT_OPTIONS, "nosniff");
|
||||||
this.expectedHeaders.add(XFrameOptionsServerHttpHeadersWriter.X_FRAME_OPTIONS, "DENY");
|
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
|
@Test
|
||||||
|
@ -62,7 +62,7 @@ class HeadersDslTests {
|
|||||||
header { string(HttpHeaders.CACHE_CONTROL, "no-cache, no-store, max-age=0, must-revalidate") }
|
header { string(HttpHeaders.CACHE_CONTROL, "no-cache, no-store, max-age=0, must-revalidate") }
|
||||||
header { string(HttpHeaders.EXPIRES, "0") }
|
header { string(HttpHeaders.EXPIRES, "0") }
|
||||||
header { string(HttpHeaders.PRAGMA, "no-cache") }
|
header { string(HttpHeaders.PRAGMA, "no-cache") }
|
||||||
header { string(XXssProtectionServerHttpHeadersWriter.X_XSS_PROTECTION, "1; mode=block") }
|
header { string(XXssProtectionServerHttpHeadersWriter.X_XSS_PROTECTION, "0") }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -106,7 +106,7 @@ class HttpSecurityDslTests {
|
|||||||
string(HttpHeaders.PRAGMA, "no-cache")
|
string(HttpHeaders.PRAGMA, "no-cache")
|
||||||
}
|
}
|
||||||
header {
|
header {
|
||||||
string(XXssProtectionServerHttpHeadersWriter.X_XSS_PROTECTION, "1; mode=block")
|
string(XXssProtectionServerHttpHeadersWriter.X_XSS_PROTECTION, "0")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -36,6 +36,7 @@ import org.springframework.test.web.servlet.get
|
|||||||
* Tests for [XssProtectionConfigDsl]
|
* Tests for [XssProtectionConfigDsl]
|
||||||
*
|
*
|
||||||
* @author Eleftheria Stein
|
* @author Eleftheria Stein
|
||||||
|
* @author Daniel Garnier-Moiroux
|
||||||
*/
|
*/
|
||||||
@ExtendWith(SpringTestContextExtension::class)
|
@ExtendWith(SpringTestContextExtension::class)
|
||||||
class XssProtectionConfigDslTests {
|
class XssProtectionConfigDslTests {
|
||||||
@ -52,7 +53,7 @@ class XssProtectionConfigDslTests {
|
|||||||
this.mockMvc.get("/") {
|
this.mockMvc.get("/") {
|
||||||
secure = true
|
secure = true
|
||||||
}.andExpect {
|
}.andExpect {
|
||||||
header { string(XXssProtectionServerHttpHeadersWriter.X_XSS_PROTECTION, "1; mode=block") }
|
header { string(XXssProtectionServerHttpHeadersWriter.X_XSS_PROTECTION, "0") }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -71,62 +72,6 @@ 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()
|
|
||||||
|
|
||||||
this.mockMvc.get("/") {
|
|
||||||
secure = true
|
|
||||||
}.andExpect {
|
|
||||||
header { string(XXssProtectionServerHttpHeadersWriter.X_XSS_PROTECTION, "1") }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Configuration
|
|
||||||
@EnableWebSecurity
|
|
||||||
open class XssProtectionBlockFalseConfig {
|
|
||||||
@Bean
|
|
||||||
open fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
|
|
||||||
http {
|
|
||||||
headers {
|
|
||||||
defaultsDisabled = true
|
|
||||||
xssProtection {
|
|
||||||
block = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return http.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `headers when XSS protection disabled then X-XSS-Protection header is 0`() {
|
|
||||||
this.spring.register(XssProtectionDisabledConfig::class.java).autowire()
|
|
||||||
|
|
||||||
this.mockMvc.get("/") {
|
|
||||||
secure = true
|
|
||||||
}.andExpect {
|
|
||||||
header { string(XXssProtectionServerHttpHeadersWriter.X_XSS_PROTECTION, "0") }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Configuration
|
|
||||||
@EnableWebSecurity
|
|
||||||
open class XssProtectionDisabledConfig {
|
|
||||||
@Bean
|
|
||||||
open fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
|
|
||||||
http {
|
|
||||||
headers {
|
|
||||||
defaultsDisabled = true
|
|
||||||
xssProtection {
|
|
||||||
xssProtectionEnabled = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return http.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `headers when XSS protection disabled then X-XSS-Protection header not in response`() {
|
fun `headers when XSS protection disabled then X-XSS-Protection header not in response`() {
|
||||||
this.spring.register(XssProtectionDisabledFunctionConfig::class.java).autowire()
|
this.spring.register(XssProtectionDisabledFunctionConfig::class.java).autowire()
|
||||||
@ -155,26 +100,54 @@ class XssProtectionConfigDslTests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `headers when XSS protection header value disabled then X-XSS-Protection header is 0`() {
|
fun `headers when XSS protection header value enabled then X-XSS-Protection header is 1`() {
|
||||||
this.spring.register(XssProtectionHeaderValueDisabledFunctionConfig::class.java).autowire()
|
this.spring.register(XssProtectionHeaderValueEnabledFunctionConfig::class.java).autowire()
|
||||||
|
|
||||||
this.mockMvc.get("/") {
|
this.mockMvc.get("/") {
|
||||||
secure = true
|
secure = true
|
||||||
}.andExpect {
|
}.andExpect {
|
||||||
header { string(XXssProtectionServerHttpHeadersWriter.X_XSS_PROTECTION, "0") }
|
header { string(XXssProtectionServerHttpHeadersWriter.X_XSS_PROTECTION, "1") }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
@EnableWebSecurity
|
@EnableWebSecurity
|
||||||
open class XssProtectionHeaderValueDisabledFunctionConfig () {
|
open class XssProtectionHeaderValueEnabledFunctionConfig {
|
||||||
@Bean
|
@Bean
|
||||||
open fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
|
open fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
|
||||||
http {
|
http {
|
||||||
headers {
|
headers {
|
||||||
defaultsDisabled = true
|
defaultsDisabled = true
|
||||||
xssProtection {
|
xssProtection {
|
||||||
headerValue = XXssProtectionHeaderWriter.HeaderValue.DISABLED
|
headerValue = XXssProtectionHeaderWriter.HeaderValue.ENABLED
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return http.build()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
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, "1; mode=block") }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@EnableWebSecurity
|
||||||
|
open class XssProtectionHeaderValueEnabledModeBlockFunctionConfig {
|
||||||
|
@Bean
|
||||||
|
open fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
|
||||||
|
http {
|
||||||
|
headers {
|
||||||
|
defaultsDisabled = true
|
||||||
|
xssProtection {
|
||||||
|
headerValue = XXssProtectionHeaderWriter.HeaderValue.ENABLED_MODE_BLOCK
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -71,7 +71,7 @@ class ServerHeadersDslTests {
|
|||||||
.expectHeader().valueEquals(HttpHeaders.CACHE_CONTROL, "no-cache, no-store, max-age=0, must-revalidate")
|
.expectHeader().valueEquals(HttpHeaders.CACHE_CONTROL, "no-cache, no-store, max-age=0, must-revalidate")
|
||||||
.expectHeader().valueEquals(HttpHeaders.EXPIRES, "0")
|
.expectHeader().valueEquals(HttpHeaders.EXPIRES, "0")
|
||||||
.expectHeader().valueEquals(HttpHeaders.PRAGMA, "no-cache")
|
.expectHeader().valueEquals(HttpHeaders.PRAGMA, "no-cache")
|
||||||
.expectHeader().valueEquals(XXssProtectionServerHttpHeadersWriter.X_XSS_PROTECTION, "1 ; mode=block")
|
.expectHeader().valueEquals(XXssProtectionServerHttpHeadersWriter.X_XSS_PROTECTION, "0")
|
||||||
}
|
}
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
|
@ -126,7 +126,7 @@ class ServerHttpSecurityDslTests {
|
|||||||
.expectHeader().valueEquals(HttpHeaders.CACHE_CONTROL, "no-cache, no-store, max-age=0, must-revalidate")
|
.expectHeader().valueEquals(HttpHeaders.CACHE_CONTROL, "no-cache, no-store, max-age=0, must-revalidate")
|
||||||
.expectHeader().valueEquals(HttpHeaders.EXPIRES, "0")
|
.expectHeader().valueEquals(HttpHeaders.EXPIRES, "0")
|
||||||
.expectHeader().valueEquals(HttpHeaders.PRAGMA, "no-cache")
|
.expectHeader().valueEquals(HttpHeaders.PRAGMA, "no-cache")
|
||||||
.expectHeader().valueEquals(XXssProtectionServerHttpHeadersWriter.X_XSS_PROTECTION, "1 ; mode=block")
|
.expectHeader().valueEquals(XXssProtectionServerHttpHeadersWriter.X_XSS_PROTECTION, "0")
|
||||||
}
|
}
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
|
@ -57,7 +57,7 @@ class ServerXssProtectionDslTests {
|
|||||||
this.client.get()
|
this.client.get()
|
||||||
.uri("/")
|
.uri("/")
|
||||||
.exchange()
|
.exchange()
|
||||||
.expectHeader().valueEquals(XXssProtectionServerHttpHeadersWriter.X_XSS_PROTECTION, "1 ; mode=block")
|
.expectHeader().valueEquals(XXssProtectionServerHttpHeadersWriter.X_XSS_PROTECTION, "0")
|
||||||
}
|
}
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
@ -107,7 +107,7 @@ class ServerXssProtectionDslTests {
|
|||||||
this.client.get()
|
this.client.get()
|
||||||
.uri("/")
|
.uri("/")
|
||||||
.exchange()
|
.exchange()
|
||||||
.expectHeader().valueEquals(XXssProtectionServerHttpHeadersWriter.X_XSS_PROTECTION, "0")
|
.expectHeader().valueEquals(XXssProtectionServerHttpHeadersWriter.X_XSS_PROTECTION, "1")
|
||||||
}
|
}
|
||||||
|
|
||||||
@EnableWebFluxSecurity
|
@EnableWebFluxSecurity
|
||||||
@ -118,7 +118,7 @@ class ServerXssProtectionDslTests {
|
|||||||
return http {
|
return http {
|
||||||
headers {
|
headers {
|
||||||
xssProtection {
|
xssProtection {
|
||||||
headerValue = XXssProtectionServerHttpHeadersWriter.HeaderValue.DISABLED
|
headerValue = XXssProtectionServerHttpHeadersWriter.HeaderValue.ENABLED
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -33,7 +33,7 @@ Expires: 0
|
|||||||
X-Content-Type-Options: nosniff
|
X-Content-Type-Options: nosniff
|
||||||
Strict-Transport-Security: max-age=31536000 ; includeSubDomains
|
Strict-Transport-Security: max-age=31536000 ; includeSubDomains
|
||||||
X-Frame-Options: DENY
|
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].
|
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:
|
By default, Spring Security blocks the content by using the following header:
|
||||||
|
|
||||||
====
|
====
|
||||||
[source]
|
[source]
|
||||||
----
|
----
|
||||||
X-XSS-Protection: 1; mode=block
|
X-XSS-Protection: 0
|
||||||
----
|
----
|
||||||
====
|
====
|
||||||
|
|
||||||
|
@ -255,8 +255,8 @@ fun webFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain {
|
|||||||
|
|
||||||
[[webflux-headers-xss-protection]]
|
[[webflux-headers-xss-protection]]
|
||||||
== X-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>.
|
||||||
You can disable `X-XSS-Protection`:
|
You can disable the `X-XSS-Protection` header entirely:
|
||||||
|
|
||||||
.X-XSS-Protection Customization
|
.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]]
|
[[webflux-headers-csp]]
|
||||||
== Content Security Policy (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.
|
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.
|
||||||
|
@ -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.
|
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]]
|
[[nsa-xss-protection-header-value]]
|
||||||
* **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.
|
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".
|
One of: "0", "1", "1; mode=block". Defaults to "0".
|
||||||
When set, overrides both enabled and block attributes.
|
|
||||||
|
|
||||||
|
|
||||||
[[nsa-xss-protection-parents]]
|
[[nsa-xss-protection-parents]]
|
||||||
|
@ -529,9 +529,10 @@ class SecurityConfig {
|
|||||||
[[servlet-headers-xss-protection]]
|
[[servlet-headers-xss-protection]]
|
||||||
== X-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.
|
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
|
.X-XSS-Protection Customization
|
||||||
====
|
====
|
||||||
@ -548,7 +549,7 @@ public class WebSecurityConfig {
|
|||||||
// ...
|
// ...
|
||||||
.headers(headers -> headers
|
.headers(headers -> headers
|
||||||
.xssProtection(xss -> xss
|
.xssProtection(xss -> xss
|
||||||
.block(false)
|
.headerValue(XXssProtectionHeaderWriter.HeaderValue.ENABLED_MODE_BLOCK)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
return http.build();
|
return http.build();
|
||||||
@ -563,7 +564,7 @@ public class WebSecurityConfig {
|
|||||||
<!-- ... -->
|
<!-- ... -->
|
||||||
|
|
||||||
<headers>
|
<headers>
|
||||||
<xss-protection block="false"/>
|
<xss-protection headerValue="1; mode=block"/>
|
||||||
</headers>
|
</headers>
|
||||||
</http>
|
</http>
|
||||||
----
|
----
|
||||||
@ -581,7 +582,7 @@ class SecurityConfig {
|
|||||||
http {
|
http {
|
||||||
headers {
|
headers {
|
||||||
xssProtection {
|
xssProtection {
|
||||||
block = false
|
headerValue = XXssProtectionHeaderWriter.HeaderValue.ENABLED_MODE_BLOCK
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,6 +29,7 @@ import org.springframework.util.Assert;
|
|||||||
*
|
*
|
||||||
* @author Rob Winch
|
* @author Rob Winch
|
||||||
* @author Ankur Pathak
|
* @author Ankur Pathak
|
||||||
|
* @author Daniel Garnier-Moiroux
|
||||||
* @since 3.2
|
* @since 3.2
|
||||||
*/
|
*/
|
||||||
public final class XXssProtectionHeaderWriter implements HeaderWriter {
|
public final class XXssProtectionHeaderWriter implements HeaderWriter {
|
||||||
@ -41,7 +42,7 @@ public final class XXssProtectionHeaderWriter implements HeaderWriter {
|
|||||||
* Create a new instance
|
* Create a new instance
|
||||||
*/
|
*/
|
||||||
public XXssProtectionHeaderWriter() {
|
public XXssProtectionHeaderWriter() {
|
||||||
this.headerValue = HeaderValue.ENABLED_MODE_BLOCK;
|
this.headerValue = HeaderValue.DISABLED;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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.
|
* Sets the value of the X-XSS-PROTECTION header.
|
||||||
* <p>
|
* <p>
|
||||||
|
@ -41,7 +41,7 @@ public class XXssProtectionServerHttpHeadersWriter implements ServerHttpHeadersW
|
|||||||
* Creates a new instance
|
* Creates a new instance
|
||||||
*/
|
*/
|
||||||
public XXssProtectionServerHttpHeadersWriter() {
|
public XXssProtectionServerHttpHeadersWriter() {
|
||||||
this.headerValue = HeaderValue.ENABLED_MODE_BLOCK;
|
this.headerValue = HeaderValue.DISABLED;
|
||||||
updateDelegate();
|
updateDelegate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -51,57 +51,8 @@ public class XXssProtectionServerHttpHeadersWriter implements ServerHttpHeadersW
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If true, will contain a value of 1. For example:
|
* Sets the value of the X-XSS-PROTECTION header. Defaults to
|
||||||
*
|
* {@link HeaderValue#DISABLED}
|
||||||
* <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.
|
|
||||||
* <p>
|
* <p>
|
||||||
* If {@link HeaderValue#DISABLED}, will specify that X-XSS-Protection is disabled.
|
* If {@link HeaderValue#DISABLED}, will specify that X-XSS-Protection is disabled.
|
||||||
* For example:
|
* For example:
|
||||||
|
@ -28,6 +28,7 @@ import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException
|
|||||||
/**
|
/**
|
||||||
* @author Rob Winch
|
* @author Rob Winch
|
||||||
* @author Ankur Pathak
|
* @author Ankur Pathak
|
||||||
|
* @author Daniel Garnier-Moiroux
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class XXssProtectionHeaderWriterTests {
|
public class XXssProtectionHeaderWriterTests {
|
||||||
@ -49,43 +50,11 @@ public class XXssProtectionHeaderWriterTests {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void writeHeaders() {
|
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);
|
this.writer.writeHeaders(this.request, this.response);
|
||||||
assertThat(this.response.getHeaderNames()).hasSize(1);
|
assertThat(this.response.getHeaderNames()).hasSize(1);
|
||||||
assertThat(this.response.getHeaderValues("X-XSS-Protection")).containsOnly("0");
|
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
|
@Test
|
||||||
public void writeHeaderWhenNotPresent() {
|
public void writeHeaderWhenNotPresent() {
|
||||||
String value = new String("value");
|
String value = new String("value");
|
||||||
|
@ -46,23 +46,6 @@ public class XXssProtectionServerHttpHeadersWriterTests {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void writeHeadersWhenNoHeadersThenWriteHeaders() {
|
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);
|
this.writer.writeHttpHeaders(this.exchange);
|
||||||
assertThat(this.headers).hasSize(1);
|
assertThat(this.headers).hasSize(1);
|
||||||
assertThat(this.headers.get(XXssProtectionServerHttpHeadersWriter.X_XSS_PROTECTION)).containsOnly("0");
|
assertThat(this.headers.get(XXssProtectionServerHttpHeadersWriter.X_XSS_PROTECTION)).containsOnly("0");
|
||||||
|
Loading…
x
Reference in New Issue
Block a user