parent
eb2870bf82
commit
23294c4c57
|
@ -221,7 +221,7 @@ public final class SecurityNamespaceHandler implements NamespaceHandler {
|
||||||
private boolean matchesVersionInternal(Element element) {
|
private boolean matchesVersionInternal(Element element) {
|
||||||
String schemaLocation = element.getAttributeNS(
|
String schemaLocation = element.getAttributeNS(
|
||||||
"http://www.w3.org/2001/XMLSchema-instance", "schemaLocation");
|
"http://www.w3.org/2001/XMLSchema-instance", "schemaLocation");
|
||||||
return schemaLocation.matches("(?m).*spring-security-4\\.1.*.xsd.*")
|
return schemaLocation.matches("(?m).*spring-security-4\\.2.*.xsd.*")
|
||||||
|| schemaLocation.matches("(?m).*spring-security.xsd.*")
|
|| schemaLocation.matches("(?m).*spring-security.xsd.*")
|
||||||
|| !schemaLocation.matches("(?m).*spring-security.*");
|
|| !schemaLocation.matches("(?m).*spring-security.*");
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,6 +28,7 @@ import org.springframework.security.config.annotation.web.configuration.WebSecur
|
||||||
import org.springframework.security.web.header.HeaderWriter;
|
import org.springframework.security.web.header.HeaderWriter;
|
||||||
import org.springframework.security.web.header.HeaderWriterFilter;
|
import org.springframework.security.web.header.HeaderWriterFilter;
|
||||||
import org.springframework.security.web.header.writers.*;
|
import org.springframework.security.web.header.writers.*;
|
||||||
|
import org.springframework.security.web.header.writers.ReferrerPolicyHeaderWriter.ReferrerPolicy;
|
||||||
import org.springframework.security.web.header.writers.frameoptions.XFrameOptionsHeaderWriter;
|
import org.springframework.security.web.header.writers.frameoptions.XFrameOptionsHeaderWriter;
|
||||||
import org.springframework.security.web.header.writers.frameoptions.XFrameOptionsHeaderWriter.XFrameOptionsMode;
|
import org.springframework.security.web.header.writers.frameoptions.XFrameOptionsHeaderWriter.XFrameOptionsMode;
|
||||||
import org.springframework.security.web.util.matcher.RequestMatcher;
|
import org.springframework.security.web.util.matcher.RequestMatcher;
|
||||||
|
@ -56,6 +57,7 @@ import org.springframework.util.Assert;
|
||||||
* @author Rob Winch
|
* @author Rob Winch
|
||||||
* @author Tim Ysewyn
|
* @author Tim Ysewyn
|
||||||
* @author Joe Grandja
|
* @author Joe Grandja
|
||||||
|
* @author Eddú Meléndez
|
||||||
* @since 3.2
|
* @since 3.2
|
||||||
*/
|
*/
|
||||||
public class HeadersConfigurer<H extends HttpSecurityBuilder<H>> extends
|
public class HeadersConfigurer<H extends HttpSecurityBuilder<H>> extends
|
||||||
|
@ -78,6 +80,8 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>> extends
|
||||||
|
|
||||||
private final ContentSecurityPolicyConfig contentSecurityPolicy = new ContentSecurityPolicyConfig();
|
private final ContentSecurityPolicyConfig contentSecurityPolicy = new ContentSecurityPolicyConfig();
|
||||||
|
|
||||||
|
private final ReferrerPolicyConfig referrerPolicy = new ReferrerPolicyConfig();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new instance
|
* Creates a new instance
|
||||||
*
|
*
|
||||||
|
@ -770,6 +774,7 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>> extends
|
||||||
addIfNotNull(writers, frameOptions.writer);
|
addIfNotNull(writers, frameOptions.writer);
|
||||||
addIfNotNull(writers, hpkp.writer);
|
addIfNotNull(writers, hpkp.writer);
|
||||||
addIfNotNull(writers, contentSecurityPolicy.writer);
|
addIfNotNull(writers, contentSecurityPolicy.writer);
|
||||||
|
addIfNotNull(writers, referrerPolicy.writer);
|
||||||
writers.addAll(headerWriters);
|
writers.addAll(headerWriters);
|
||||||
return writers;
|
return writers;
|
||||||
}
|
}
|
||||||
|
@ -779,4 +784,68 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>> extends
|
||||||
values.add(value);
|
values.add(value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* Allows configuration for <a href="https://www.w3.org/TR/referrer-policy/">Referrer Policy</a>.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Configuration is provided to the {@link ReferrerPolicyHeaderWriter} which support the writing
|
||||||
|
* of the header as detailed in the W3C Technical Report:
|
||||||
|
* </p>
|
||||||
|
* <ul>
|
||||||
|
* <li>Referrer-Policy</li>
|
||||||
|
* </ul>
|
||||||
|
*
|
||||||
|
* <p>Default value is:</p>
|
||||||
|
*
|
||||||
|
* <pre>
|
||||||
|
* Referrer-Policy: no-referrer
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* @see ReferrerPolicyHeaderWriter
|
||||||
|
* @since 4.2
|
||||||
|
* @return the ReferrerPolicyConfig for additional configuration
|
||||||
|
*/
|
||||||
|
public ReferrerPolicyConfig referrerPolicy() {
|
||||||
|
this.referrerPolicy.writer = new ReferrerPolicyHeaderWriter();
|
||||||
|
return this.referrerPolicy;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* Allows configuration for <a href="https://www.w3.org/TR/referrer-policy/">Referrer Policy</a>.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Configuration is provided to the {@link ReferrerPolicyHeaderWriter} which support the writing
|
||||||
|
* of the header as detailed in the W3C Technical Report:
|
||||||
|
* </p>
|
||||||
|
* <ul>
|
||||||
|
* <li>Referrer-Policy</li>
|
||||||
|
* </ul>
|
||||||
|
*
|
||||||
|
* @see ReferrerPolicyHeaderWriter
|
||||||
|
* @since 4.2
|
||||||
|
* @return the ReferrerPolicyConfig for additional configuration
|
||||||
|
* @throws IllegalArgumentException if policy is null or empty
|
||||||
|
*/
|
||||||
|
public ReferrerPolicyConfig referrerPolicy(ReferrerPolicy policy) {
|
||||||
|
this.referrerPolicy.writer = new ReferrerPolicyHeaderWriter(policy);
|
||||||
|
return this.referrerPolicy;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class ReferrerPolicyConfig {
|
||||||
|
|
||||||
|
private ReferrerPolicyHeaderWriter writer;
|
||||||
|
|
||||||
|
private ReferrerPolicyConfig() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public HeadersConfigurer<H> and() {
|
||||||
|
return HeadersConfigurer.this;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -31,6 +31,7 @@ import org.springframework.beans.factory.xml.BeanDefinitionParser;
|
||||||
import org.springframework.beans.factory.xml.ParserContext;
|
import org.springframework.beans.factory.xml.ParserContext;
|
||||||
import org.springframework.security.web.header.HeaderWriterFilter;
|
import org.springframework.security.web.header.HeaderWriterFilter;
|
||||||
import org.springframework.security.web.header.writers.*;
|
import org.springframework.security.web.header.writers.*;
|
||||||
|
import org.springframework.security.web.header.writers.ReferrerPolicyHeaderWriter.ReferrerPolicy;
|
||||||
import org.springframework.security.web.header.writers.frameoptions.RegExpAllowFromStrategy;
|
import org.springframework.security.web.header.writers.frameoptions.RegExpAllowFromStrategy;
|
||||||
import org.springframework.security.web.header.writers.frameoptions.StaticAllowFromStrategy;
|
import org.springframework.security.web.header.writers.frameoptions.StaticAllowFromStrategy;
|
||||||
import org.springframework.security.web.header.writers.frameoptions.WhiteListedAllowFromStrategy;
|
import org.springframework.security.web.header.writers.frameoptions.WhiteListedAllowFromStrategy;
|
||||||
|
@ -45,6 +46,7 @@ import org.w3c.dom.Node;
|
||||||
*
|
*
|
||||||
* @author Marten Deinum
|
* @author Marten Deinum
|
||||||
* @author Tim Ysewyn
|
* @author Tim Ysewyn
|
||||||
|
* @author Eddú Meléndez
|
||||||
* @since 3.2
|
* @since 3.2
|
||||||
*/
|
*/
|
||||||
public class HeadersBeanDefinitionParser implements BeanDefinitionParser {
|
public class HeadersBeanDefinitionParser implements BeanDefinitionParser {
|
||||||
|
@ -82,6 +84,7 @@ public class HeadersBeanDefinitionParser implements BeanDefinitionParser {
|
||||||
private static final String GENERIC_HEADER_ELEMENT = "header";
|
private static final String GENERIC_HEADER_ELEMENT = "header";
|
||||||
|
|
||||||
private static final String CONTENT_SECURITY_POLICY_ELEMENT = "content-security-policy";
|
private static final String CONTENT_SECURITY_POLICY_ELEMENT = "content-security-policy";
|
||||||
|
private static final String REFERRER_POLICY_ELEMENT = "referrer-policy";
|
||||||
|
|
||||||
private static final String ALLOW_FROM = "ALLOW-FROM";
|
private static final String ALLOW_FROM = "ALLOW-FROM";
|
||||||
|
|
||||||
|
@ -109,6 +112,8 @@ public class HeadersBeanDefinitionParser implements BeanDefinitionParser {
|
||||||
|
|
||||||
parseContentSecurityPolicyElement(disabled, element, parserContext);
|
parseContentSecurityPolicyElement(disabled, element, parserContext);
|
||||||
|
|
||||||
|
parseReferrerPolicyElement(element, parserContext);
|
||||||
|
|
||||||
parseHeaderElements(element);
|
parseHeaderElements(element);
|
||||||
|
|
||||||
boolean noWriters = headerWriters.isEmpty();
|
boolean noWriters = headerWriters.isEmpty();
|
||||||
|
@ -291,6 +296,23 @@ public class HeadersBeanDefinitionParser implements BeanDefinitionParser {
|
||||||
headerWriters.add(headersWriter.getBeanDefinition());
|
headerWriters.add(headersWriter.getBeanDefinition());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void parseReferrerPolicyElement(Element element, ParserContext context) {
|
||||||
|
Element referrerPolicyElement = (element == null) ? null : DomUtils.getChildElementByTagName(element, REFERRER_POLICY_ELEMENT);
|
||||||
|
if (referrerPolicyElement != null) {
|
||||||
|
addReferrerPolicy(referrerPolicyElement, context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addReferrerPolicy(Element referrerPolicyElement, ParserContext context) {
|
||||||
|
BeanDefinitionBuilder headersWriter = BeanDefinitionBuilder.genericBeanDefinition(ReferrerPolicyHeaderWriter.class);
|
||||||
|
|
||||||
|
String policy = referrerPolicyElement.getAttribute(ATT_POLICY);
|
||||||
|
if (StringUtils.hasLength(policy)) {
|
||||||
|
headersWriter.addConstructorArgValue(ReferrerPolicy.get(policy));
|
||||||
|
}
|
||||||
|
headerWriters.add(headersWriter.getBeanDefinition());
|
||||||
|
}
|
||||||
|
|
||||||
private void attrNotAllowed(ParserContext context, String attrName,
|
private void attrNotAllowed(ParserContext context, String attrName,
|
||||||
String otherAttrName, Element element) {
|
String otherAttrName, Element element) {
|
||||||
context.getReaderContext().error(
|
context.getReaderContext().error(
|
||||||
|
|
|
@ -753,7 +753,7 @@ csrf-options.attlist &=
|
||||||
|
|
||||||
headers =
|
headers =
|
||||||
## Element for configuration of the HeaderWritersFilter. Enables easy setting for the X-Frame-Options, X-XSS-Protection and X-Content-Type-Options headers.
|
## Element for configuration of the HeaderWritersFilter. Enables easy setting for the X-Frame-Options, X-XSS-Protection and X-Content-Type-Options headers.
|
||||||
element headers { headers-options.attlist, (cache-control? & xss-protection? & hsts? & frame-options? & content-type-options? & hpkp? & content-security-policy? & header*)}
|
element headers { headers-options.attlist, (cache-control? & xss-protection? & hsts? & frame-options? & content-type-options? & hpkp? & content-security-policy? & referrer-policy? & header*)}
|
||||||
headers-options.attlist &=
|
headers-options.attlist &=
|
||||||
## Specifies if the default headers should be disabled. Default false.
|
## Specifies if the default headers should be disabled. Default false.
|
||||||
attribute defaults-disabled {xsd:boolean}?
|
attribute defaults-disabled {xsd:boolean}?
|
||||||
|
@ -824,6 +824,13 @@ csp-options.attlist &=
|
||||||
## Set to true, to enable the Content-Security-Policy-Report-Only header for reporting policy violations only. Defaults to false.
|
## Set to true, to enable the Content-Security-Policy-Report-Only header for reporting policy violations only. Defaults to false.
|
||||||
attribute report-only {xsd:boolean}?
|
attribute report-only {xsd:boolean}?
|
||||||
|
|
||||||
|
referrer-policy =
|
||||||
|
## Adds support for Referrer Policy
|
||||||
|
element referrer-policy {referrer-options.attlist}
|
||||||
|
referrer-options.attlist &=
|
||||||
|
## The policies for the Referrer-Policy header.
|
||||||
|
attribute policy {"no-referrer","no-referrer-when-downgrade","same-origin","origin","strict-origin","origin-when-cross-origin","strict-origin-when-cross-origin","unsafe-url"}?
|
||||||
|
|
||||||
cache-control =
|
cache-control =
|
||||||
## Adds Cache-Control no-cache, no-store, must-revalidate, Pragma no-cache, and Expires 0 for every request
|
## Adds Cache-Control no-cache, no-store, must-revalidate, Pragma no-cache, and Expires 0 for every request
|
||||||
element cache-control {cache-control.attlist}
|
element cache-control {cache-control.attlist}
|
||||||
|
|
|
@ -2357,6 +2357,7 @@
|
||||||
<xs:element ref="security:content-type-options"/>
|
<xs:element ref="security:content-type-options"/>
|
||||||
<xs:element ref="security:hpkp"/>
|
<xs:element ref="security:hpkp"/>
|
||||||
<xs:element ref="security:content-security-policy"/>
|
<xs:element ref="security:content-security-policy"/>
|
||||||
|
<xs:element ref="security:referrer-policy"/>
|
||||||
<xs:element ref="security:header"/>
|
<xs:element ref="security:header"/>
|
||||||
</xs:choice>
|
</xs:choice>
|
||||||
<xs:attributeGroup ref="security:headers-options.attlist"/>
|
<xs:attributeGroup ref="security:headers-options.attlist"/>
|
||||||
|
@ -2539,6 +2540,35 @@
|
||||||
</xs:annotation>
|
</xs:annotation>
|
||||||
</xs:attribute>
|
</xs:attribute>
|
||||||
</xs:attributeGroup>
|
</xs:attributeGroup>
|
||||||
|
<xs:element name="referrer-policy">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation>Adds support for Referrer Policy
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
<xs:complexType>
|
||||||
|
<xs:attributeGroup ref="security:referrer-options.attlist"/>
|
||||||
|
</xs:complexType>
|
||||||
|
</xs:element>
|
||||||
|
<xs:attributeGroup name="referrer-options.attlist">
|
||||||
|
<xs:attribute name="policy">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation>The policies for the Referrer-Policy header.
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
<xs:simpleType>
|
||||||
|
<xs:restriction base="xs:token">
|
||||||
|
<xs:enumeration value="no-referrer"/>
|
||||||
|
<xs:enumeration value="no-referrer-when-downgrade"/>
|
||||||
|
<xs:enumeration value="same-origin"/>
|
||||||
|
<xs:enumeration value="origin"/>
|
||||||
|
<xs:enumeration value="strict-origin"/>
|
||||||
|
<xs:enumeration value="origin-when-cross-origin"/>
|
||||||
|
<xs:enumeration value="strict-origin-when-cross-origin"/>
|
||||||
|
<xs:enumeration value="unsafe-url"/>
|
||||||
|
</xs:restriction>
|
||||||
|
</xs:simpleType>
|
||||||
|
</xs:attribute>
|
||||||
|
</xs:attributeGroup>
|
||||||
<xs:element name="cache-control">
|
<xs:element name="cache-control">
|
||||||
<xs:annotation>
|
<xs:annotation>
|
||||||
<xs:documentation>Adds Cache-Control no-cache, no-store, must-revalidate, Pragma no-cache, and Expires 0 for
|
<xs:documentation>Adds Cache-Control no-cache, no-store, must-revalidate, Pragma no-cache, and Expires 0 for
|
||||||
|
|
|
@ -20,12 +20,14 @@ import org.springframework.security.config.annotation.BaseSpringSpec
|
||||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity
|
import org.springframework.security.config.annotation.web.builders.HttpSecurity
|
||||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity
|
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity
|
||||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter
|
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter
|
||||||
|
import static org.springframework.security.web.header.writers.ReferrerPolicyHeaderWriter.ReferrerPolicy
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @author Rob Winch
|
* @author Rob Winch
|
||||||
* @author Tim Ysewyn
|
* @author Tim Ysewyn
|
||||||
* @author Joe Grandja
|
* @author Joe Grandja
|
||||||
|
* @author Eddú Meléndez
|
||||||
*/
|
*/
|
||||||
class HeadersConfigurerTests extends BaseSpringSpec {
|
class HeadersConfigurerTests extends BaseSpringSpec {
|
||||||
|
|
||||||
|
@ -453,4 +455,46 @@ class HeadersConfigurerTests extends BaseSpringSpec {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def "headers.referrerPolicy default"() {
|
||||||
|
setup:
|
||||||
|
loadConfig(ReferrerPolicyDefaultConfig)
|
||||||
|
when:
|
||||||
|
springSecurityFilterChain.doFilter(request,response,chain)
|
||||||
|
then:
|
||||||
|
responseHeaders == ['Referrer-Policy': 'no-referrer']
|
||||||
|
}
|
||||||
|
|
||||||
|
@EnableWebSecurity
|
||||||
|
static class ReferrerPolicyDefaultConfig extends WebSecurityConfigurerAdapter {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void configure(HttpSecurity http) throws Exception {
|
||||||
|
http
|
||||||
|
.headers()
|
||||||
|
.defaultsDisabled()
|
||||||
|
.referrerPolicy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def "headers.referrerPolicy custom"() {
|
||||||
|
setup:
|
||||||
|
loadConfig(ReferrerPolicyCustomConfig)
|
||||||
|
when:
|
||||||
|
springSecurityFilterChain.doFilter(request,response,chain)
|
||||||
|
then:
|
||||||
|
responseHeaders == ['Referrer-Policy': 'same-origin']
|
||||||
|
}
|
||||||
|
|
||||||
|
@EnableWebSecurity
|
||||||
|
static class ReferrerPolicyCustomConfig extends WebSecurityConfigurerAdapter {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void configure(HttpSecurity http) throws Exception {
|
||||||
|
http
|
||||||
|
.headers()
|
||||||
|
.defaultsDisabled()
|
||||||
|
.referrerPolicy(ReferrerPolicy.SAME_ORIGIN);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -920,6 +920,38 @@ class HttpHeadersConfigTests extends AbstractHttpConfigTests {
|
||||||
assertHeaders(response, expectedHeaders)
|
assertHeaders(response, expectedHeaders)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def 'http headers defaults : referrer-policy'() {
|
||||||
|
setup:
|
||||||
|
httpAutoConfig {
|
||||||
|
'headers'('defaults-disabled':true) {
|
||||||
|
'referrer-policy'()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
createAppContext()
|
||||||
|
when:
|
||||||
|
def hf = getFilter(HeaderWriterFilter)
|
||||||
|
MockHttpServletResponse response = new MockHttpServletResponse()
|
||||||
|
hf.doFilter(new MockHttpServletRequest(), response, new MockFilterChain())
|
||||||
|
then:
|
||||||
|
assertHeaders(response, ['Referrer-Policy': 'no-referrer'])
|
||||||
|
}
|
||||||
|
|
||||||
|
def 'http headers defaults : referrer-policy same-origin'() {
|
||||||
|
setup:
|
||||||
|
httpAutoConfig {
|
||||||
|
'headers'('defaults-disabled':true) {
|
||||||
|
'referrer-policy'('policy': 'same-origin')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
createAppContext()
|
||||||
|
when:
|
||||||
|
def hf = getFilter(HeaderWriterFilter)
|
||||||
|
MockHttpServletResponse response = new MockHttpServletResponse()
|
||||||
|
hf.doFilter(new MockHttpServletRequest(), response, new MockFilterChain())
|
||||||
|
then:
|
||||||
|
assertHeaders(response, ['Referrer-Policy': 'same-origin'])
|
||||||
|
}
|
||||||
|
|
||||||
def assertHeaders(MockHttpServletResponse response, Map<String,String> expected) {
|
def assertHeaders(MockHttpServletResponse response, Map<String,String> expected) {
|
||||||
assert response.headerNames == expected.keySet()
|
assert response.headerNames == expected.keySet()
|
||||||
expected.each { headerName, value ->
|
expected.each { headerName, value ->
|
||||||
|
|
|
@ -40,7 +40,7 @@ public class InMemoryXmlApplicationContext extends AbstractXmlApplicationContext
|
||||||
+ "http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-";
|
+ "http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-";
|
||||||
static final String BEANS_CLOSE = "</b:beans>\n";
|
static final String BEANS_CLOSE = "</b:beans>\n";
|
||||||
|
|
||||||
static final String SPRING_SECURITY_VERSION = "4.1";
|
static final String SPRING_SECURITY_VERSION = "4.2";
|
||||||
|
|
||||||
Resource inMemoryXml;
|
Resource inMemoryXml;
|
||||||
|
|
||||||
|
|
|
@ -4353,6 +4353,57 @@ protected void configure(HttpSecurity http) throws Exception {
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
[[headers-referrer]]
|
||||||
|
==== Referrer Policy
|
||||||
|
|
||||||
|
https://www.w3.org/TR/referrer-policy[Referrer Policy] is a mechanism that web applications can leverage to manage the referrer field, which contains the last
|
||||||
|
page the user was on.
|
||||||
|
|
||||||
|
Spring Security's approach is to use https://www.w3.org/TR/referrer-policy/[Referrer Policy] header, which provides different https://www.w3.org/TR/referrer-policy/#referrer-policies[policies]:
|
||||||
|
|
||||||
|
[source]
|
||||||
|
----
|
||||||
|
Referrer-Policy: same-origin
|
||||||
|
----
|
||||||
|
|
||||||
|
The Referrer-Policy response header instructs the browser to let the destination knows the source where the user was previously.
|
||||||
|
|
||||||
|
[[headers-referrer-configure]]
|
||||||
|
===== Configuring Referrer Policy
|
||||||
|
|
||||||
|
Spring Security *_doesn't add_* Referrer Policy header by default.
|
||||||
|
|
||||||
|
You can enable the Referrer-Policy header using XML configuration with the <<nsa-referrer-policy,<referrer-policy>>> element as shown below:
|
||||||
|
|
||||||
|
[source,xml]
|
||||||
|
----
|
||||||
|
<http>
|
||||||
|
<!-- ... -->
|
||||||
|
|
||||||
|
<headers>
|
||||||
|
<referrer-policy policy="same-origin" />
|
||||||
|
</headers>
|
||||||
|
</http>
|
||||||
|
----
|
||||||
|
|
||||||
|
Similarly, you can enable the Referrer Policy header using Java configuration as shown below:
|
||||||
|
|
||||||
|
[source,java]
|
||||||
|
----
|
||||||
|
@EnableWebSecurity
|
||||||
|
public class WebSecurityConfig extends
|
||||||
|
WebSecurityConfigurerAdapter {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void configure(HttpSecurity http) throws Exception {
|
||||||
|
http
|
||||||
|
// ...
|
||||||
|
.headers()
|
||||||
|
.referrerPolicy(ReferrerPolicy.SAME_ORIGIN);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
----
|
||||||
|
|
||||||
[[headers-csp-links]]
|
[[headers-csp-links]]
|
||||||
===== Additional Resources
|
===== Additional Resources
|
||||||
|
|
||||||
|
@ -7685,6 +7736,7 @@ This element allows for configuring additional (security) headers to be send wit
|
||||||
** `X-Content-Type-Options` - Can be set using the <<nsa-content-type-options,content-type-options>> element. The http://blogs.msdn.com/b/ie/archive/2008/09/02/ie8-security-part-vi-beta-2-update.aspx[X-Content-Type-Options] header prevents Internet Explorer from MIME-sniffing a response away from the declared content-type. This also applies to Google Chrome, when downloading extensions.
|
** `X-Content-Type-Options` - Can be set using the <<nsa-content-type-options,content-type-options>> element. The http://blogs.msdn.com/b/ie/archive/2008/09/02/ie8-security-part-vi-beta-2-update.aspx[X-Content-Type-Options] header prevents Internet Explorer from MIME-sniffing a response away from the declared content-type. This also applies to Google Chrome, when downloading extensions.
|
||||||
** `Public-Key-Pinning` or `Public-Key-Pinning-Report-Only` - Can be set using the <<nsa-hpkp,hpkp>> element. This allows HTTPS websites to resist impersonation by attackers using mis-issued or otherwise fraudulent certificates.
|
** `Public-Key-Pinning` or `Public-Key-Pinning-Report-Only` - Can be set using the <<nsa-hpkp,hpkp>> element. This allows HTTPS websites to resist impersonation by attackers using mis-issued or otherwise fraudulent certificates.
|
||||||
** `Content-Security-Policy` or `Content-Security-Policy-Report-Only` - Can be set using the <<nsa-content-security-policy,content-security-policy>> element. https://www.w3.org/TR/CSP2/[Content Security Policy (CSP)] is a mechanism that web applications can leverage to mitigate content injection vulnerabilities, such as cross-site scripting (XSS).
|
** `Content-Security-Policy` or `Content-Security-Policy-Report-Only` - Can be set using the <<nsa-content-security-policy,content-security-policy>> element. https://www.w3.org/TR/CSP2/[Content Security Policy (CSP)] is a mechanism that web applications can leverage to mitigate content injection vulnerabilities, such as cross-site scripting (XSS).
|
||||||
|
** `Referrer-Policy` - Can be set using the <<nsa-referrer-policy,referrer-policy>> element, https://www.w3.org/TR/referrer-policy/[Referrer-Policy] is a mechanism that web applications can leverage to manage the referrer field, which contains the last page the user was on.
|
||||||
|
|
||||||
[[nsa-headers-attributes]]
|
[[nsa-headers-attributes]]
|
||||||
===== <headers> Attributes
|
===== <headers> Attributes
|
||||||
|
@ -7718,6 +7770,7 @@ Optional attribute that specifies to disable Spring Security's HTTP response hea
|
||||||
* <<nsa-header,header>>
|
* <<nsa-header,header>>
|
||||||
* <<nsa-hpkp,hpkp>>
|
* <<nsa-hpkp,hpkp>>
|
||||||
* <<nsa-hsts,hsts>>
|
* <<nsa-hsts,hsts>>
|
||||||
|
* <<nsa-referrer-policy,referrer-policy>>
|
||||||
* <<nsa-xss-protection,xss-protection>>
|
* <<nsa-xss-protection,xss-protection>>
|
||||||
|
|
||||||
|
|
||||||
|
@ -7867,6 +7920,24 @@ Set to true, to enable the Content-Security-Policy-Report-Only header for report
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[[nsa-referrer-policy]]
|
||||||
|
==== <referrer-policy>
|
||||||
|
When enabled adds the https://www.w3.org/TR/referrer-policy/[Referrer Policy] header to the response.
|
||||||
|
|
||||||
|
[[nsa-referrer-policy-attributes]]
|
||||||
|
===== <referrer-policy> Attributes
|
||||||
|
|
||||||
|
[[nsa-referrer-policy-policy]]
|
||||||
|
* **policy**
|
||||||
|
The policy for the Referrer-Policy header. Default "no-referrer".
|
||||||
|
|
||||||
|
[[nsa-referrer-policy-parents]]
|
||||||
|
===== Parent Elements of <referrer-policy>
|
||||||
|
|
||||||
|
* <<nsa-headers,headers>>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[[nsa-frame-options]]
|
[[nsa-frame-options]]
|
||||||
==== <frame-options>
|
==== <frame-options>
|
||||||
When enabled adds the http://tools.ietf.org/html/draft-ietf-websec-x-frame-options[X-Frame-Options header] to the response, this allows newer browsers to do some security checks and prevent http://en.wikipedia.org/wiki/Clickjacking[clickjacking] attacks.
|
When enabled adds the http://tools.ietf.org/html/draft-ietf-websec-x-frame-options[X-Frame-Options header] to the response, this allows newer browsers to do some security checks and prevent http://en.wikipedia.org/wiki/Clickjacking[clickjacking] attacks.
|
||||||
|
|
|
@ -0,0 +1,129 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2002-2016 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
|
||||||
|
*
|
||||||
|
* http://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.
|
||||||
|
*/
|
||||||
|
package org.springframework.security.web.header.writers;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
|
import org.springframework.security.web.header.HeaderWriter;
|
||||||
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* Provides support for <a href="https://www.w3.org/TR/referrer-policy/">Referrer Policy</a>.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* The list of policies defined can be found at
|
||||||
|
* <a href="https://www.w3.org/TR/referrer-policy/#referrer-policies">Referrer Policies</a>.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* This implementation of {@link HeaderWriter} writes the following header:
|
||||||
|
* </p>
|
||||||
|
* <ul>
|
||||||
|
* <li>Referrer-Policy</li>
|
||||||
|
* </ul>
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* By default, the Referrer-Policy header is not included in the response.
|
||||||
|
* Policy <b>no-referrer</b> is used by default if no {@link ReferrerPolicy} is set.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author Eddú Meléndez
|
||||||
|
* @since 4.2
|
||||||
|
*/
|
||||||
|
public class ReferrerPolicyHeaderWriter implements HeaderWriter {
|
||||||
|
|
||||||
|
private final String REFERER_POLICY_HEADER = "Referrer-Policy";
|
||||||
|
|
||||||
|
private ReferrerPolicy policy;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new instance. Default value: no-referrer.
|
||||||
|
*/
|
||||||
|
public ReferrerPolicyHeaderWriter() {
|
||||||
|
this(ReferrerPolicy.NO_REFERRER);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new instance.
|
||||||
|
*
|
||||||
|
* @param policy
|
||||||
|
* @throws IllegalArgumentException if policyDirectives is null or empty
|
||||||
|
*/
|
||||||
|
public ReferrerPolicyHeaderWriter(ReferrerPolicy policy) {
|
||||||
|
setPolicy(policy);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the policy to be used in the response header.
|
||||||
|
* @param policy
|
||||||
|
*/
|
||||||
|
public void setPolicy(ReferrerPolicy policy) {
|
||||||
|
Assert.notNull(policy, "policy can not be null");
|
||||||
|
this.policy = policy;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see org.springframework.security.web.header.HeaderWriter#writeHeaders(HttpServletRequest, HttpServletResponse)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void writeHeaders(HttpServletRequest request, HttpServletResponse response) {
|
||||||
|
response.setHeader(REFERER_POLICY_HEADER, this.policy.getPolicy());
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum ReferrerPolicy {
|
||||||
|
|
||||||
|
NO_REFERRER("no-referrer"),
|
||||||
|
NO_REFERRER_WHEN_DOWNGRADE("no-referrer-when-downgrade"),
|
||||||
|
SAME_ORIGIN("same-origin"),
|
||||||
|
ORIGIN("origin"),
|
||||||
|
STRICT_ORIGIN("strict-origin"),
|
||||||
|
ORIGIN_WHEN_CROSS_ORIGIN("origin-when-cross-origin"),
|
||||||
|
STRICT_ORIGIN_WHEN_CROSS_ORIGIN("strict-origin-when-cross-origin"),
|
||||||
|
UNSAFE_URL("unsafe-url");
|
||||||
|
|
||||||
|
private static Map<String, ReferrerPolicy> REFERRER_POLICIES;
|
||||||
|
|
||||||
|
static {
|
||||||
|
Map<String, ReferrerPolicy> referrerPolicies = new HashMap<String, ReferrerPolicy>();
|
||||||
|
for (ReferrerPolicy referrerPolicy : values()) {
|
||||||
|
referrerPolicies.put(referrerPolicy.getPolicy(), referrerPolicy);
|
||||||
|
}
|
||||||
|
REFERRER_POLICIES = Collections.unmodifiableMap(referrerPolicies);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String policy;
|
||||||
|
|
||||||
|
private ReferrerPolicy(String policy) {
|
||||||
|
this.policy = policy;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPolicy() {
|
||||||
|
return this.policy;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ReferrerPolicy get(String referrerPolicy) {
|
||||||
|
return REFERRER_POLICIES.get(referrerPolicy);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,68 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2002-2016 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
|
||||||
|
*
|
||||||
|
* http://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.
|
||||||
|
*/
|
||||||
|
package org.springframework.security.web.header.writers;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import org.springframework.mock.web.MockHttpServletRequest;
|
||||||
|
import org.springframework.mock.web.MockHttpServletResponse;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.springframework.security.web.header.writers.ReferrerPolicyHeaderWriter.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Eddú Meléndez
|
||||||
|
*/
|
||||||
|
public class ReferrerPolicyHeaderWriterTests {
|
||||||
|
|
||||||
|
private final String DEFAULT_REFERRER_POLICY = "no-referrer";
|
||||||
|
private MockHttpServletRequest request;
|
||||||
|
private MockHttpServletResponse response;
|
||||||
|
private ReferrerPolicyHeaderWriter writer;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setup() {
|
||||||
|
this.request = new MockHttpServletRequest();
|
||||||
|
this.request.setSecure(true);
|
||||||
|
this.response = new MockHttpServletResponse();
|
||||||
|
this.writer = new ReferrerPolicyHeaderWriter();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void writeHeadersReferrerPolicyDefault() {
|
||||||
|
this.writer.writeHeaders(this.request, this.response);
|
||||||
|
|
||||||
|
assertThat(this.response.getHeaderNames().size()).isEqualTo(1);
|
||||||
|
assertThat(this.response.getHeader("Referrer-Policy")).isEqualTo(DEFAULT_REFERRER_POLICY);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void writeHeadersReferrerPolicyCustom() {
|
||||||
|
this.writer = new ReferrerPolicyHeaderWriter(ReferrerPolicy.SAME_ORIGIN);
|
||||||
|
|
||||||
|
this.writer.writeHeaders(this.request, this.response);
|
||||||
|
|
||||||
|
assertThat(this.response.getHeaderNames().size()).isEqualTo(1);
|
||||||
|
assertThat(this.response.getHeader("Referrer-Policy")).isEqualTo("same-origin");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = IllegalArgumentException.class)
|
||||||
|
public void writeHeaderReferrerPolicyInvalid() {
|
||||||
|
this.writer = new ReferrerPolicyHeaderWriter(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue