You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1285 lines
27 KiB
1285 lines
27 KiB
[[servlet-headers]] |
|
= Security HTTP Response Headers |
|
|
|
You can use xref:features/exploits/headers.adoc#headers[Security HTTP Response Headers] to increase the security of web applications. |
|
This section is dedicated to servlet-based support for Security HTTP Response Headers. |
|
|
|
[[servlet-headers-default]] |
|
== Default Security Headers |
|
|
|
Spring Security provides a xref:features/exploits/headers.adoc#headers-default[default set of Security HTTP Response Headers] to provide secure defaults. |
|
While each of these headers are considered best practice, it should be noted that not all clients use the headers, so additional testing is encouraged. |
|
|
|
You can customize specific headers. |
|
For example, assume that you want the defaults but you wish to specify `SAMEORIGIN` for <<servlet-headers-frame-options,X-Frame-Options>>. |
|
|
|
You can do so with the following configuration: |
|
|
|
.Customize Default Security Headers |
|
[tabs] |
|
====== |
|
Java:: |
|
+ |
|
[source,java,role="primary"] |
|
---- |
|
@Configuration |
|
@EnableWebSecurity |
|
public class WebSecurityConfig { |
|
|
|
@Bean |
|
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { |
|
http |
|
// ... |
|
.headers((headers) -> headers |
|
.frameOptions((frameOptions) -> frameOptions |
|
.sameOrigin() |
|
) |
|
); |
|
return http.build(); |
|
} |
|
} |
|
---- |
|
|
|
XML:: |
|
+ |
|
[source,xml,role="secondary"] |
|
---- |
|
<http> |
|
<!-- ... --> |
|
|
|
<headers> |
|
<frame-options policy="SAMEORIGIN" /> |
|
</headers> |
|
</http> |
|
---- |
|
|
|
Kotlin:: |
|
+ |
|
[source,kotlin,role="secondary"] |
|
---- |
|
@Configuration |
|
@EnableWebSecurity |
|
class SecurityConfig { |
|
@Bean |
|
open fun filterChain(http: HttpSecurity): SecurityFilterChain { |
|
http { |
|
// ... |
|
headers { |
|
frameOptions { |
|
sameOrigin = true |
|
} |
|
} |
|
} |
|
return http.build() |
|
} |
|
} |
|
---- |
|
====== |
|
|
|
If you do not want the defaults to be added and want explicit control over what should be used, you can disable the defaults. |
|
The next code listing shows how to do so. |
|
|
|
If you use Spring Security's configuration, the following adds only xref:features/exploits/headers.adoc#headers-cache-control[Cache Control]: |
|
|
|
.Customize Cache Control Headers |
|
[tabs] |
|
====== |
|
Java:: |
|
+ |
|
[source,java,role="primary"] |
|
---- |
|
@Configuration |
|
@EnableWebSecurity |
|
public class WebSecurityConfig { |
|
|
|
@Bean |
|
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { |
|
http |
|
// ... |
|
.headers((headers) -> headers |
|
// do not use any default headers unless explicitly listed |
|
.defaultsDisabled() |
|
.cacheControl(withDefaults()) |
|
); |
|
return http.build(); |
|
} |
|
} |
|
---- |
|
|
|
XML:: |
|
+ |
|
[source,xml,role="secondary"] |
|
---- |
|
<http> |
|
<!-- ... --> |
|
|
|
<headers defaults-disabled="true"> |
|
<cache-control/> |
|
</headers> |
|
</http> |
|
---- |
|
|
|
Kotlin:: |
|
+ |
|
[source,kotlin,role="secondary"] |
|
---- |
|
@Configuration |
|
@EnableWebSecurity |
|
class SecurityConfig { |
|
@Bean |
|
open fun filterChain(http: HttpSecurity): SecurityFilterChain { |
|
http { |
|
// ... |
|
headers { |
|
// do not use any default headers unless explicitly listed |
|
defaultsDisabled = true |
|
cacheControl { |
|
} |
|
} |
|
} |
|
return http.build() |
|
} |
|
} |
|
---- |
|
====== |
|
|
|
If necessary, you can disable all of the HTTP Security response headers with the following configuration: |
|
|
|
.Disable All HTTP Security Headers |
|
[tabs] |
|
====== |
|
Java:: |
|
+ |
|
[source,java,role="primary"] |
|
---- |
|
@Configuration |
|
@EnableWebSecurity |
|
public class WebSecurityConfig { |
|
|
|
@Bean |
|
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { |
|
http |
|
// ... |
|
.headers((headers) -> headers.disable()); |
|
return http.build(); |
|
} |
|
} |
|
---- |
|
|
|
XML:: |
|
+ |
|
[source,xml,role="secondary"] |
|
---- |
|
<http> |
|
<!-- ... --> |
|
|
|
<headers disabled="true" /> |
|
</http> |
|
---- |
|
|
|
Kotlin:: |
|
+ |
|
[source,kotlin,role="secondary"] |
|
---- |
|
@Configuration |
|
@EnableWebSecurity |
|
class SecurityConfig { |
|
@Bean |
|
open fun filterChain(http: HttpSecurity): SecurityFilterChain { |
|
http { |
|
// ... |
|
headers { |
|
disable() |
|
} |
|
} |
|
return http.build() |
|
} |
|
} |
|
---- |
|
====== |
|
|
|
[[servlet-headers-cache-control]] |
|
== Cache Control |
|
|
|
Spring Security includes xref:features/exploits/headers.adoc#headers-cache-control[Cache Control] headers by default. |
|
|
|
However, if you actually want to cache specific responses, your application can selectively invoke https://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletResponse.html#setHeader(java.lang.String,java.lang.String)[`HttpServletResponse.setHeader(String,String)`] to override the header set by Spring Security. |
|
You can use this to ensure that content (such as CSS, JavaScript, and images) is properly cached. |
|
|
|
When you use Spring Web MVC, this is typically done within your configuration. |
|
You can find details on how to do this in the https://docs.spring.io/spring/docs/5.0.0.RELEASE/spring-framework-reference/web.html#mvc-config-static-resources[Static Resources] portion of the Spring Reference documentation |
|
|
|
If necessary, you can also disable Spring Security's cache control HTTP response headers. |
|
|
|
.Cache Control Disabled |
|
[tabs] |
|
====== |
|
Java:: |
|
+ |
|
[source,java,role="primary"] |
|
---- |
|
@Configuration |
|
@EnableWebSecurity |
|
public class WebSecurityConfig { |
|
|
|
@Bean |
|
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { |
|
http |
|
// ... |
|
.headers((headers) -> headers |
|
.cacheControl((cache) -> cache.disable()) |
|
); |
|
return http.build(); |
|
} |
|
} |
|
---- |
|
|
|
XML:: |
|
+ |
|
[source,xml,role="secondary"] |
|
---- |
|
<http> |
|
<!-- ... --> |
|
|
|
<headers> |
|
<cache-control disabled="true"/> |
|
</headers> |
|
</http> |
|
---- |
|
|
|
Kotlin:: |
|
+ |
|
[source,kotlin,role="secondary"] |
|
---- |
|
@Configuration |
|
@EnableWebSecurity |
|
class SecurityConfig { |
|
|
|
@Bean |
|
open fun filterChain(http: HttpSecurity): SecurityFilterChain { |
|
http { |
|
headers { |
|
cacheControl { |
|
disable() |
|
} |
|
} |
|
} |
|
return http.build() |
|
} |
|
} |
|
---- |
|
====== |
|
|
|
[[servlet-headers-content-type-options]] |
|
== Content Type Options |
|
|
|
Spring Security includes xref:features/exploits/headers.adoc#headers-content-type-options[Content-Type] headers by default. |
|
However, you can disable it: |
|
|
|
.Content Type Options Disabled |
|
[tabs] |
|
====== |
|
Java:: |
|
+ |
|
[source,java,role="primary"] |
|
---- |
|
@Configuration |
|
@EnableWebSecurity |
|
public class WebSecurityConfig { |
|
|
|
@Bean |
|
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { |
|
http |
|
// ... |
|
.headers((headers) -> headers |
|
.contentTypeOptions((contentTypeOptions) -> contentTypeOptions.disable()) |
|
); |
|
return http.build(); |
|
} |
|
} |
|
---- |
|
|
|
XML:: |
|
+ |
|
[source,xml,role="secondary"] |
|
---- |
|
<http> |
|
<!-- ... --> |
|
|
|
<headers> |
|
<content-type-options disabled="true"/> |
|
</headers> |
|
</http> |
|
---- |
|
|
|
Kotlin:: |
|
+ |
|
[source,kotlin,role="secondary"] |
|
---- |
|
@Configuration |
|
@EnableWebSecurity |
|
class SecurityConfig { |
|
|
|
@Bean |
|
open fun filterChain(http: HttpSecurity): SecurityFilterChain { |
|
http { |
|
headers { |
|
contentTypeOptions { |
|
disable() |
|
} |
|
} |
|
} |
|
return http.build() |
|
} |
|
} |
|
---- |
|
====== |
|
|
|
[[servlet-headers-hsts]] |
|
== HTTP Strict Transport Security (HSTS) |
|
|
|
By default, Spring Security provides the xref:features/exploits/headers.adoc#headers-hsts[Strict Transport Security] header. |
|
However, you can explicitly customize the results. |
|
The following example explicitly provides HSTS: |
|
|
|
.Strict Transport Security |
|
[tabs] |
|
====== |
|
Java:: |
|
+ |
|
[source,java,role="primary"] |
|
---- |
|
@Configuration |
|
@EnableWebSecurity |
|
public class WebSecurityConfig { |
|
|
|
@Bean |
|
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { |
|
http |
|
// ... |
|
.headers((headers) -> headers |
|
.httpStrictTransportSecurity((hsts) -> hsts |
|
.includeSubDomains(true) |
|
.preload(true) |
|
.maxAgeInSeconds(31536000) |
|
) |
|
); |
|
return http.build(); |
|
} |
|
} |
|
---- |
|
|
|
XML:: |
|
+ |
|
[source,xml,role="secondary"] |
|
---- |
|
<http> |
|
<!-- ... --> |
|
|
|
<headers> |
|
<hsts |
|
include-subdomains="true" |
|
max-age-seconds="31536000" |
|
preload="true" /> |
|
</headers> |
|
</http> |
|
---- |
|
|
|
Kotlin:: |
|
+ |
|
[source,kotlin,role="secondary"] |
|
---- |
|
@Configuration |
|
@EnableWebSecurity |
|
class SecurityConfig { |
|
|
|
@Bean |
|
open fun filterChain(http: HttpSecurity): SecurityFilterChain { |
|
http { |
|
headers { |
|
httpStrictTransportSecurity { |
|
includeSubDomains = true |
|
preload = true |
|
maxAgeInSeconds = 31536000 |
|
} |
|
} |
|
} |
|
return http.build() |
|
} |
|
} |
|
---- |
|
====== |
|
|
|
[[servlet-headers-hpkp]] |
|
== HTTP Public Key Pinning (HPKP) |
|
Spring Security provides servlet support for xref:features/exploits/headers.adoc#headers-hpkp[HTTP Public Key Pinning], but it is xref:features/exploits/headers.adoc#headers-hpkp-deprecated[no longer recommended]. |
|
|
|
You can enable HPKP headers with the following configuration: |
|
|
|
.HTTP Public Key Pinning |
|
[tabs] |
|
====== |
|
Java:: |
|
+ |
|
[source,java,role="primary"] |
|
---- |
|
@Configuration |
|
@EnableWebSecurity |
|
public class WebSecurityConfig { |
|
|
|
@Bean |
|
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { |
|
http |
|
// ... |
|
.headers((headers) -> headers |
|
.httpPublicKeyPinning((hpkp) -> hpkp |
|
.includeSubDomains(true) |
|
.reportUri("https://example.net/pkp-report") |
|
.addSha256Pins("d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=", "E9CZ9INDbd+2eRQozYqqbQ2yXLVKB9+xcprMF+44U1g=") |
|
) |
|
); |
|
return http.build(); |
|
} |
|
} |
|
---- |
|
|
|
XML:: |
|
+ |
|
[source,xml,role="secondary"] |
|
---- |
|
<http> |
|
<!-- ... --> |
|
|
|
<headers> |
|
<hpkp |
|
include-subdomains="true" |
|
report-uri="https://example.net/pkp-report"> |
|
<pins> |
|
<pin algorithm="sha256">d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=</pin> |
|
<pin algorithm="sha256">E9CZ9INDbd+2eRQozYqqbQ2yXLVKB9+xcprMF+44U1g=</pin> |
|
</pins> |
|
</hpkp> |
|
</headers> |
|
</http> |
|
---- |
|
|
|
Kotlin:: |
|
+ |
|
[source,kotlin,role="secondary"] |
|
---- |
|
@Configuration |
|
@EnableWebSecurity |
|
class SecurityConfig { |
|
|
|
@Bean |
|
open fun filterChain(http: HttpSecurity): SecurityFilterChain { |
|
http { |
|
headers { |
|
httpPublicKeyPinning { |
|
includeSubDomains = true |
|
reportUri = "https://example.net/pkp-report" |
|
pins = mapOf("d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=" to "sha256", |
|
"E9CZ9INDbd+2eRQozYqqbQ2yXLVKB9+xcprMF+44U1g=" to "sha256") |
|
} |
|
} |
|
} |
|
return http.build() |
|
} |
|
} |
|
---- |
|
====== |
|
|
|
[[servlet-headers-frame-options]] |
|
== X-Frame-Options |
|
|
|
By default, Spring Security instructs browsers to block reflected XSS attacks by using the xref:features/exploits/headers.adoc#headers-frame-options[X-Frame-Options]. |
|
|
|
For example, the following configuration specifies that Spring Security should no longer instruct browsers to block the content: |
|
|
|
.X-Frame-Options: SAMEORIGIN |
|
[tabs] |
|
====== |
|
Java:: |
|
+ |
|
[source,java,role="primary"] |
|
---- |
|
@Configuration |
|
@EnableWebSecurity |
|
public class WebSecurityConfig { |
|
|
|
@Bean |
|
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { |
|
http |
|
// ... |
|
.headers((headers) -> headers |
|
.frameOptions((frameOptions) -> frameOptions |
|
.sameOrigin() |
|
) |
|
); |
|
return http.build(); |
|
} |
|
} |
|
---- |
|
|
|
XML:: |
|
+ |
|
[source,xml,role="secondary"] |
|
---- |
|
<http> |
|
<!-- ... --> |
|
|
|
<headers> |
|
<frame-options |
|
policy="SAMEORIGIN" /> |
|
</headers> |
|
</http> |
|
---- |
|
|
|
|
|
Kotlin:: |
|
+ |
|
[source,kotlin,role="secondary"] |
|
---- |
|
@Configuration |
|
@EnableWebSecurity |
|
class SecurityConfig { |
|
|
|
@Bean |
|
open fun filterChain(http: HttpSecurity): SecurityFilterChain { |
|
http { |
|
headers { |
|
frameOptions { |
|
sameOrigin = true |
|
} |
|
} |
|
} |
|
return http.build() |
|
} |
|
} |
|
---- |
|
====== |
|
|
|
[[servlet-headers-xss-protection]] |
|
== X-XSS-Protection |
|
|
|
By default, Spring Security instructs browsers to disable the XSS Auditor by using <<headers-xss-protection,X-XSS-Protection header>. |
|
However, you can change this default. |
|
For example, the following configuration specifies that Spring Security instruct compatible browsers to enable filtering, |
|
and block the content: |
|
|
|
.X-XSS-Protection Customization |
|
[tabs] |
|
====== |
|
Java:: |
|
+ |
|
[source,java,role="primary"] |
|
---- |
|
@Configuration |
|
@EnableWebSecurity |
|
public class WebSecurityConfig { |
|
|
|
@Bean |
|
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { |
|
http |
|
// ... |
|
.headers((headers) -> headers |
|
.xssProtection((xss) -> xss |
|
.headerValue(XXssProtectionHeaderWriter.HeaderValue.ENABLED_MODE_BLOCK) |
|
) |
|
); |
|
return http.build(); |
|
} |
|
} |
|
---- |
|
|
|
XML:: |
|
+ |
|
[source,xml,role="secondary"] |
|
---- |
|
<http> |
|
<!-- ... --> |
|
|
|
<headers> |
|
<xss-protection headerValue="1; mode=block"/> |
|
</headers> |
|
</http> |
|
---- |
|
|
|
Kotlin:: |
|
+ |
|
[source,kotlin,role="secondary"] |
|
---- |
|
@Configuration |
|
@EnableWebSecurity |
|
class SecurityConfig { |
|
|
|
@Bean |
|
open fun filterChain(http: HttpSecurity): SecurityFilterChain { |
|
// ... |
|
http { |
|
headers { |
|
xssProtection { |
|
headerValue = XXssProtectionHeaderWriter.HeaderValue.ENABLED_MODE_BLOCK |
|
} |
|
} |
|
} |
|
return http.build() |
|
} |
|
} |
|
---- |
|
====== |
|
|
|
[[servlet-headers-csp]] |
|
== Content Security Policy (CSP) |
|
|
|
Spring Security does not add xref:features/exploits/headers.adoc#headers-csp[Content Security Policy] by default, because a reasonable default is impossible to know without knowing the context of the application. |
|
The web application author must declare the security policy (or policies) to enforce or monitor for the protected resources. |
|
|
|
Consider the following security policy: |
|
|
|
.Content Security Policy Example |
|
[source,http] |
|
---- |
|
Content-Security-Policy: script-src 'self' https://trustedscripts.example.com; object-src https://trustedplugins.example.com; report-uri /csp-report-endpoint/ |
|
---- |
|
|
|
Given the preceding security policy, you can enable the CSP header: |
|
|
|
.Content Security Policy |
|
[tabs] |
|
====== |
|
Java:: |
|
+ |
|
[source,java,role="primary"] |
|
---- |
|
@Configuration |
|
@EnableWebSecurity |
|
public class WebSecurityConfig { |
|
|
|
@Bean |
|
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { |
|
http |
|
// ... |
|
.headers((headers) -> headers |
|
.contentSecurityPolicy((csp) -> csp |
|
.policyDirectives("script-src 'self' https://trustedscripts.example.com; object-src https://trustedplugins.example.com; report-uri /csp-report-endpoint/") |
|
) |
|
); |
|
return http.build(); |
|
} |
|
} |
|
---- |
|
|
|
XML:: |
|
+ |
|
[source,xml,role="secondary"] |
|
---- |
|
<http> |
|
<!-- ... --> |
|
|
|
<headers> |
|
<content-security-policy |
|
policy-directives="script-src 'self' https://trustedscripts.example.com; object-src https://trustedplugins.example.com; report-uri /csp-report-endpoint/" /> |
|
</headers> |
|
</http> |
|
---- |
|
|
|
Kotlin:: |
|
+ |
|
[source,kotlin,role="secondary"] |
|
---- |
|
@Configuration |
|
@EnableWebSecurity |
|
class SecurityConfig { |
|
|
|
@Bean |
|
open fun filterChain(http: HttpSecurity): SecurityFilterChain { |
|
http { |
|
// ... |
|
headers { |
|
contentSecurityPolicy { |
|
policyDirectives = "script-src 'self' https://trustedscripts.example.com; object-src https://trustedplugins.example.com; report-uri /csp-report-endpoint/" |
|
} |
|
} |
|
} |
|
return http.build() |
|
} |
|
} |
|
---- |
|
====== |
|
|
|
To enable the CSP `report-only` header, provide the following configuration: |
|
|
|
.Content Security Policy Report Only |
|
[tabs] |
|
====== |
|
Java:: |
|
+ |
|
[source,java,role="primary"] |
|
---- |
|
@Configuration |
|
@EnableWebSecurity |
|
public class WebSecurityConfig { |
|
|
|
@Bean |
|
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { |
|
http |
|
// ... |
|
.headers((headers) -> headers |
|
.contentSecurityPolicy((csp) -> csp |
|
.policyDirectives("script-src 'self' https://trustedscripts.example.com; object-src https://trustedplugins.example.com; report-uri /csp-report-endpoint/") |
|
.reportOnly() |
|
) |
|
); |
|
return http.build(); |
|
} |
|
} |
|
---- |
|
|
|
XML:: |
|
+ |
|
[source,xml,role="secondary"] |
|
---- |
|
<http> |
|
<!-- ... --> |
|
|
|
<headers> |
|
<content-security-policy |
|
policy-directives="script-src 'self' https://trustedscripts.example.com; object-src https://trustedplugins.example.com; report-uri /csp-report-endpoint/" |
|
report-only="true" /> |
|
</headers> |
|
</http> |
|
---- |
|
|
|
Kotlin:: |
|
+ |
|
[source,kotlin,role="secondary"] |
|
---- |
|
@Configuration |
|
@EnableWebSecurity |
|
class SecurityConfig { |
|
|
|
@Bean |
|
open fun filterChain(http: HttpSecurity): SecurityFilterChain { |
|
http { |
|
// ... |
|
headers { |
|
contentSecurityPolicy { |
|
policyDirectives = "script-src 'self' https://trustedscripts.example.com; object-src https://trustedplugins.example.com; report-uri /csp-report-endpoint/" |
|
reportOnly = true |
|
} |
|
} |
|
} |
|
return http.build() |
|
} |
|
} |
|
---- |
|
====== |
|
|
|
[[servlet-headers-referrer]] |
|
== Referrer Policy |
|
|
|
Spring Security does not add xref:features/exploits/headers.adoc#headers-referrer[Referrer Policy] headers by default. |
|
You can enable the Referrer Policy header by using the configuration: |
|
|
|
.Referrer Policy |
|
[tabs] |
|
====== |
|
Java:: |
|
+ |
|
[source,java,role="primary"] |
|
---- |
|
@Configuration |
|
@EnableWebSecurity |
|
public class WebSecurityConfig { |
|
|
|
@Bean |
|
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { |
|
http |
|
// ... |
|
.headers((headers) -> headers |
|
.referrerPolicy((referrer) -> referrer |
|
.policy(ReferrerPolicy.SAME_ORIGIN) |
|
) |
|
); |
|
return http.build(); |
|
} |
|
} |
|
---- |
|
|
|
XML:: |
|
+ |
|
[source,xml,role="secondary"] |
|
---- |
|
<http> |
|
<!-- ... --> |
|
|
|
<headers> |
|
<referrer-policy policy="same-origin" /> |
|
</headers> |
|
</http> |
|
---- |
|
|
|
Kotlin:: |
|
+ |
|
[source,kotlin,role="secondary"] |
|
---- |
|
@Configuration |
|
@EnableWebSecurity |
|
class SecurityConfig { |
|
|
|
@Bean |
|
open fun filterChain(http: HttpSecurity): SecurityFilterChain { |
|
http { |
|
// ... |
|
headers { |
|
referrerPolicy { |
|
policy = ReferrerPolicy.SAME_ORIGIN |
|
} |
|
} |
|
} |
|
return http.build() |
|
} |
|
} |
|
---- |
|
====== |
|
|
|
[[servlet-headers-feature]] |
|
== Feature Policy |
|
|
|
Spring Security does not add xref:features/exploits/headers.adoc#headers-feature[Feature Policy] headers by default. |
|
Consider the following `Feature-Policy` header: |
|
|
|
.Feature-Policy Example |
|
[source] |
|
---- |
|
Feature-Policy: geolocation 'self' |
|
---- |
|
|
|
You can enable the preceding feature policy header by using the following configuration: |
|
|
|
.Feature-Policy |
|
[tabs] |
|
====== |
|
Java:: |
|
+ |
|
[source,java,role="primary"] |
|
---- |
|
@Configuration |
|
@EnableWebSecurity |
|
public class WebSecurityConfig { |
|
|
|
@Bean |
|
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { |
|
http |
|
// ... |
|
.headers((headers) -> headers |
|
.featurePolicy("geolocation 'self'") |
|
); |
|
return http.build(); |
|
} |
|
} |
|
---- |
|
|
|
XML:: |
|
+ |
|
[source,xml,role="secondary"] |
|
---- |
|
<http> |
|
<!-- ... --> |
|
|
|
<headers> |
|
<feature-policy policy-directives="geolocation 'self'" /> |
|
</headers> |
|
</http> |
|
---- |
|
|
|
Kotlin:: |
|
+ |
|
[source,kotlin,role="secondary"] |
|
---- |
|
@Configuration |
|
@EnableWebSecurity |
|
class SecurityConfig { |
|
|
|
@Bean |
|
open fun filterChain(http: HttpSecurity): SecurityFilterChain { |
|
http { |
|
// ... |
|
headers { |
|
featurePolicy("geolocation 'self'") |
|
} |
|
} |
|
return http.build() |
|
} |
|
} |
|
---- |
|
====== |
|
|
|
[[servlet-headers-permissions]] |
|
== Permissions Policy |
|
|
|
Spring Security does not add xref:features/exploits/headers.adoc#headers-permissions[Permissions Policy] headers by default. |
|
Consider the following `Permissions-Policy` header: |
|
|
|
.Permissions-Policy Example |
|
[source] |
|
---- |
|
Permissions-Policy: geolocation=(self) |
|
---- |
|
|
|
You can enable the preceding permissions policy header using the following configuration: |
|
|
|
.Permissions-Policy |
|
[tabs] |
|
====== |
|
Java:: |
|
+ |
|
[source,java,role="primary"] |
|
---- |
|
@Configuration |
|
@EnableWebSecurity |
|
public class WebSecurityConfig { |
|
|
|
@Bean |
|
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { |
|
http |
|
// ... |
|
.headers((headers) -> headers |
|
.permissionsPolicy((permissions) -> permissions |
|
.policy("geolocation=(self)") |
|
) |
|
); |
|
return http.build(); |
|
} |
|
} |
|
---- |
|
|
|
XML:: |
|
+ |
|
[source,xml,role="secondary"] |
|
---- |
|
<http> |
|
<!-- ... --> |
|
|
|
<headers> |
|
<permissions-policy policy="geolocation=(self)" /> |
|
</headers> |
|
</http> |
|
---- |
|
|
|
Kotlin:: |
|
+ |
|
[source,kotlin,role="secondary"] |
|
---- |
|
@Configuration |
|
@EnableWebSecurity |
|
class SecurityConfig { |
|
|
|
@Bean |
|
open fun filterChain(http: HttpSecurity): SecurityFilterChain { |
|
http { |
|
// ... |
|
headers { |
|
permissionPolicy { |
|
policy = "geolocation=(self)" |
|
} |
|
} |
|
} |
|
return http.build() |
|
} |
|
} |
|
---- |
|
====== |
|
|
|
[[servlet-headers-clear-site-data]] |
|
== Clear Site Data |
|
|
|
Spring Security does not add xref:features/exploits/headers.adoc#headers-clear-site-data[Clear-Site-Data] headers by default. |
|
Consider the following Clear-Site-Data header: |
|
|
|
.Clear-Site-Data Example |
|
---- |
|
Clear-Site-Data: "cache", "cookies" |
|
---- |
|
|
|
You can send the preceding header on log out with the following configuration: |
|
|
|
.Clear-Site-Data |
|
[tabs] |
|
====== |
|
Java:: |
|
+ |
|
[source,java,role="primary"] |
|
---- |
|
@Configuration |
|
@EnableWebSecurity |
|
public class WebSecurityConfig { |
|
|
|
@Bean |
|
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { |
|
http |
|
// ... |
|
.logout((logout) -> logout |
|
.addLogoutHandler(new HeaderWriterLogoutHandler(new ClearSiteDataHeaderWriter(CACHE, COOKIES))) |
|
); |
|
return http.build(); |
|
} |
|
} |
|
---- |
|
|
|
Kotlin:: |
|
+ |
|
[source,kotlin,role="secondary"] |
|
---- |
|
@Configuration |
|
@EnableWebSecurity |
|
class SecurityConfig { |
|
|
|
@Bean |
|
open fun filterChain(http: HttpSecurity): SecurityFilterChain { |
|
http { |
|
// ... |
|
logout { |
|
addLogoutHandler(HeaderWriterLogoutHandler(ClearSiteDataHeaderWriter(CACHE, COOKIES))) |
|
} |
|
} |
|
return http.build() |
|
} |
|
} |
|
---- |
|
====== |
|
|
|
[[servlet-headers-custom]] |
|
== Custom Headers |
|
Spring Security has mechanisms to make it convenient to add the more common security headers to your application. |
|
However, it also provides hooks to enable adding custom headers. |
|
|
|
[[servlet-headers-static]] |
|
=== Static Headers |
|
There may be times when you wish to inject custom security headers that are not supported out of the box into your application. |
|
Consider the following custom security header: |
|
|
|
[source] |
|
---- |
|
X-Custom-Security-Header: header-value |
|
---- |
|
|
|
Given the preceding header, you could add the headers to the response by using the following configuration: |
|
|
|
.StaticHeadersWriter |
|
[tabs] |
|
====== |
|
Java:: |
|
+ |
|
[source,java,role="primary"] |
|
---- |
|
@Configuration |
|
@EnableWebSecurity |
|
public class WebSecurityConfig { |
|
|
|
@Bean |
|
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { |
|
http |
|
// ... |
|
.headers((headers) -> headers |
|
.addHeaderWriter(new StaticHeadersWriter("X-Custom-Security-Header","header-value")) |
|
); |
|
return http.build(); |
|
} |
|
} |
|
---- |
|
|
|
XML:: |
|
+ |
|
[source,xml,role="secondary"] |
|
---- |
|
<http> |
|
<!-- ... --> |
|
|
|
<headers> |
|
<header name="X-Custom-Security-Header" value="header-value"/> |
|
</headers> |
|
</http> |
|
---- |
|
|
|
Kotlin:: |
|
+ |
|
[source,kotlin,role="secondary"] |
|
---- |
|
@Configuration |
|
@EnableWebSecurity |
|
class SecurityConfig { |
|
|
|
@Bean |
|
open fun filterChain(http: HttpSecurity): SecurityFilterChain { |
|
http { |
|
// ... |
|
headers { |
|
addHeaderWriter(StaticHeadersWriter("X-Custom-Security-Header","header-value")) |
|
} |
|
} |
|
return http.build() |
|
} |
|
} |
|
---- |
|
====== |
|
|
|
[[servlet-headers-writer]] |
|
=== Headers Writer |
|
When the namespace or Java configuration does not support the headers you want, you can create a custom `HeadersWriter` instance or even provide a custom implementation of the `HeadersWriter`. |
|
|
|
The next example use a custom instance of `XFrameOptionsHeaderWriter`. |
|
If you wanted to explicitly configure <<servlet-headers-frame-options>>, you could do so with the following configuration: |
|
|
|
.Headers Writer |
|
[tabs] |
|
====== |
|
Java:: |
|
+ |
|
[source,java,role="primary"] |
|
---- |
|
@Configuration |
|
@EnableWebSecurity |
|
public class WebSecurityConfig { |
|
|
|
@Bean |
|
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { |
|
http |
|
// ... |
|
.headers((headers) -> headers |
|
.addHeaderWriter(new XFrameOptionsHeaderWriter(XFrameOptionsMode.SAMEORIGIN)) |
|
); |
|
return http.build(); |
|
} |
|
} |
|
---- |
|
|
|
XML:: |
|
+ |
|
[source,xml,role="secondary"] |
|
---- |
|
<http> |
|
<!-- ... --> |
|
|
|
<headers> |
|
<header ref="frameOptionsWriter"/> |
|
</headers> |
|
</http> |
|
<!-- Requires the c-namespace. |
|
See https://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#beans-c-namespace |
|
--> |
|
<beans:bean id="frameOptionsWriter" |
|
class="org.springframework.security.web.header.writers.frameoptions.XFrameOptionsHeaderWriter" |
|
c:frameOptionsMode="SAMEORIGIN"/> |
|
---- |
|
|
|
Kotlin:: |
|
+ |
|
[source,kotlin,role="secondary"] |
|
---- |
|
@Configuration |
|
@EnableWebSecurity |
|
class SecurityConfig { |
|
|
|
@Bean |
|
open fun filterChain(http: HttpSecurity): SecurityFilterChain { |
|
http { |
|
// ... |
|
headers { |
|
addHeaderWriter(XFrameOptionsHeaderWriter(XFrameOptionsMode.SAMEORIGIN)) |
|
} |
|
} |
|
return http.build() |
|
} |
|
} |
|
---- |
|
====== |
|
|
|
[[headers-delegatingrequestmatcherheaderwriter]] |
|
=== DelegatingRequestMatcherHeaderWriter |
|
|
|
At times, you may want to write a header only for certain requests. |
|
For example, perhaps you want to protect only your login page from being framed. |
|
You could use the `DelegatingRequestMatcherHeaderWriter` to do so. |
|
|
|
The following configuration example uses `DelegatingRequestMatcherHeaderWriter`: |
|
|
|
.DelegatingRequestMatcherHeaderWriter Java Configuration |
|
[tabs] |
|
====== |
|
Java:: |
|
+ |
|
[source,java,role="primary"] |
|
---- |
|
@Configuration |
|
@EnableWebSecurity |
|
public class WebSecurityConfig { |
|
|
|
@Bean |
|
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { |
|
RequestMatcher matcher = new AntPathRequestMatcher("/login"); |
|
DelegatingRequestMatcherHeaderWriter headerWriter = |
|
new DelegatingRequestMatcherHeaderWriter(matcher,new XFrameOptionsHeaderWriter()); |
|
http |
|
// ... |
|
.headers((headers) -> headers |
|
.frameOptions((frameOptions) -> frameOptions.disable()) |
|
.addHeaderWriter(headerWriter) |
|
); |
|
return http.build(); |
|
} |
|
} |
|
---- |
|
|
|
XML:: |
|
+ |
|
[source,xml,role="secondary"] |
|
---- |
|
<http> |
|
<!-- ... --> |
|
|
|
<headers> |
|
<frame-options disabled="true"/> |
|
<header ref="headerWriter"/> |
|
</headers> |
|
</http> |
|
|
|
<beans:bean id="headerWriter" |
|
class="org.springframework.security.web.header.writers.DelegatingRequestMatcherHeaderWriter"> |
|
<beans:constructor-arg> |
|
<bean class="org.springframework.security.web.util.matcher.AntPathRequestMatcher" |
|
c:pattern="/login"/> |
|
</beans:constructor-arg> |
|
<beans:constructor-arg> |
|
<beans:bean |
|
class="org.springframework.security.web.header.writers.frameoptions.XFrameOptionsHeaderWriter"/> |
|
</beans:constructor-arg> |
|
</beans:bean> |
|
---- |
|
|
|
Kotlin:: |
|
+ |
|
[source,kotlin,role="secondary"] |
|
---- |
|
@Configuration |
|
@EnableWebSecurity |
|
class SecurityConfig { |
|
|
|
@Bean |
|
open fun filterChain(http: HttpSecurity): SecurityFilterChain { |
|
val matcher: RequestMatcher = AntPathRequestMatcher("/login") |
|
val headerWriter = DelegatingRequestMatcherHeaderWriter(matcher, XFrameOptionsHeaderWriter()) |
|
http { |
|
headers { |
|
frameOptions { |
|
disable() |
|
} |
|
addHeaderWriter(headerWriter) |
|
} |
|
} |
|
return http.build() |
|
} |
|
} |
|
---- |
|
======
|
|
|