Skip to content

Commit

Permalink
Add X-Xss-Protection headerValue to XML config
Browse files Browse the repository at this point in the history
  • Loading branch information
Kehrlann committed Oct 3, 2022
1 parent 7be2eb0 commit 8ca88d1
Show file tree
Hide file tree
Showing 11 changed files with 281 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,8 @@ public class HeadersBeanDefinitionParser implements BeanDefinitionParser {

private static final String ATT_POLICY_DIRECTIVES = "policy-directives";

private static final String ATT_HEADER_VALUE = "header-value";

private static final String CACHE_CONTROL_ELEMENT = "cache-control";

private static final String HPKP_ELEMENT = "hpkp";
Expand Down Expand Up @@ -595,6 +597,14 @@ private void parseXssElement(boolean addIfNotPresent, Element element, ParserCon
}
builder.addPropertyValue("block", block);
}
XXssProtectionHeaderWriter.HeaderValue headerValue = XXssProtectionHeaderWriter.HeaderValue
.from(xssElt.getAttribute(ATT_HEADER_VALUE));
if (headerValue != null) {
if (disabled) {
attrNotAllowed(parserContext, ATT_HEADER_VALUE, ATT_DISABLED, xssElt);
}
builder.addPropertyValue("headerValue", headerValue);
}
if (disabled) {
return;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1298,6 +1298,9 @@ xss-protection.attlist &=
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"}?

content-type-options =
## Add a X-Content-Type-Options header to the resopnse. Value is always 'nosniff'.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3649,6 +3649,20 @@
</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>
</xs:annotation>
<xs:simpleType>
<xs:restriction base="xs:token">
<xs:enumeration value="0"/>
<xs:enumeration value="1"/>
<xs:enumeration value="1\;mode=block"/>
</xs:restriction>
</xs:simpleType>
</xs:attribute>
</xs:attributeGroup>
<xs:element name="content-type-options">
<xs:annotation>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -384,6 +384,58 @@ public void requestWhenDisablingXssProtectionThenDefaultsToZero() throws Excepti
// @formatter:on
}

@Test
public void requestWhenSettingXssProtectionHeaderValueToZeroThenDefaultsToZero() throws Exception {
Set<String> excludedHeaders = new HashSet<>(defaultHeaders.keySet());
excludedHeaders.remove("X-XSS-Protection");
this.spring.configLocations(this.xml("DefaultsDisabledWithXssProtectionHeaderValueZero")).autowire();
// @formatter:off
this.mvc.perform(get("/"))
.andExpect(status().isOk())
.andExpect(header().string("X-XSS-Protection", "0"))
.andExpect(excludes(excludedHeaders));
// @formatter:on
}

@Test
public void requestWhenSettingXssProtectionHeaderValueToOneThenDefaultsToOne() throws Exception {
Set<String> excludedHeaders = new HashSet<>(defaultHeaders.keySet());
excludedHeaders.remove("X-XSS-Protection");
this.spring.configLocations(this.xml("DefaultsDisabledWithXssProtectionHeaderValueOne")).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 requestWhenSettingXssProtectionHeaderValueToOneModeBlockThenDefaultsToOneModeBlock() throws Exception {
Set<String> excludedHeaders = new HashSet<>(defaultHeaders.keySet());
excludedHeaders.remove("X-XSS-Protection");
this.spring.configLocations(this.xml("DefaultsDisabledWithXssProtectionHeaderValueOneModeBlock")).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 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() {
assertThatExceptionOfType(BeanCreationException.class)
Expand Down Expand Up @@ -650,6 +702,13 @@ public void configureWhenXssProtectionDisabledAndBlockSpecifiedThenAutowireFails
.withMessageContaining("block");
}

@Test
public void configureWhenXssProtectionDisabledAndHeaderValueSpecifiedThenAutowireFails() {
assertThatExceptionOfType(BeanDefinitionParsingException.class).isThrownBy(
() -> this.spring.configLocations(this.xml("XssProtectionDisabledSpecifyingHeaderValue")).autowire())
.withMessageContaining("header-value");
}

@Test
public void configureWhenFrameOptionsDisabledAndPolicySpecifiedThenAutowireFails() {
assertThatExceptionOfType(BeanDefinitionParsingException.class)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?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>
</http>

<b:bean name="simple" class="org.springframework.security.config.http.HttpHeadersConfigTests.SimpleController"/>

<b:import resource="userservice.xml"/>
</b:beans>
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?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 header-value="1"/>
</headers>
</http>

<b:bean name="simple" class="org.springframework.security.config.http.HttpHeadersConfigTests.SimpleController"/>

<b:import resource="userservice.xml"/>
</b:beans>
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?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 header-value="1; mode=block"/>
</headers>
</http>

<b:bean name="simple" class="org.springframework.security.config.http.HttpHeadersConfigTests.SimpleController"/>

<b:import resource="userservice.xml"/>
</b:beans>
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?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 header-value="0"/>
</headers>
</http>

<b:bean name="simple" class="org.springframework.security.config.http.HttpHeadersConfigTests.SimpleController"/>

<b:import resource="userservice.xml"/>
</b:beans>
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?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>
<xss-protection disabled="true" header-value="1"/>
</headers>
</http>

<b:bean name="simple" class="org.springframework.security.config.http.HttpHeadersConfigTests.SimpleController"/>

<b:import resource="userservice.xml"/>
</b:beans>
6 changes: 6 additions & 0 deletions docs/modules/ROOT/pages/servlet/appendix/namespace/http.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -578,6 +578,12 @@ 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.


[[nsa-xss-protection-parents]]
=== Parent Elements of <xss-protection>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,15 @@ public enum HeaderValue {
this.value = value;
}

public static HeaderValue from(String headerValue) {
for (HeaderValue value : values()) {
if (value.toString().equals(headerValue)) {
return value;
}
}
return null;
}

@Override
public String toString() {
return this.value;
Expand Down

0 comments on commit 8ca88d1

Please sign in to comment.