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.
649 lines
15 KiB
649 lines
15 KiB
[[webflux-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 WebFlux-based support for Security HTTP Response Headers. |
|
|
|
[[webflux-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 xref:servlet/exploits/headers.adoc#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"] |
|
---- |
|
@Bean |
|
SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) { |
|
http |
|
// ... |
|
.headers((headers) -> headers |
|
.frameOptions((frameOptions) -> frameOptions |
|
.mode(Mode.SAMEORIGIN) |
|
) |
|
); |
|
return http.build(); |
|
} |
|
---- |
|
|
|
Kotlin:: |
|
+ |
|
[source,kotlin,role="secondary"] |
|
---- |
|
@Bean |
|
fun webFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain { |
|
return http { |
|
// ... |
|
headers { |
|
frameOptions { |
|
mode = Mode.SAMEORIGIN |
|
} |
|
} |
|
} |
|
} |
|
---- |
|
====== |
|
|
|
If you do not want the defaults to be added and want explicit control over what should be used, you can disable the defaults: |
|
|
|
|
|
.Disable HTTP Security Response Headers |
|
[tabs] |
|
====== |
|
Java:: |
|
+ |
|
[source,java,role="primary"] |
|
---- |
|
@Bean |
|
SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) { |
|
http |
|
// ... |
|
.headers((headers) -> headers.disable()); |
|
return http.build(); |
|
} |
|
---- |
|
|
|
Kotlin:: |
|
+ |
|
[source,kotlin,role="secondary"] |
|
---- |
|
@Bean |
|
fun webFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain { |
|
return http { |
|
// ... |
|
headers { |
|
disable() |
|
} |
|
} |
|
} |
|
---- |
|
====== |
|
|
|
[[webflux-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 add them to the https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/http/server/reactive/ServerHttpResponse.html[`ServerHttpResponse`] to override the header set by Spring Security. |
|
This is useful to ensure that such things as CSS, JavaScript, and images are properly cached. |
|
|
|
When using Spring WebFlux, you typically do so within your configuration. |
|
You can find details on how to do so in the https://docs.spring.io/spring/docs/5.0.0.RELEASE/spring-framework-reference/web-reactive.html#webflux-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"] |
|
---- |
|
@Bean |
|
SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) { |
|
http |
|
// ... |
|
.headers((headers) -> headers |
|
.cache((cache) -> cache.disable()) |
|
); |
|
return http.build(); |
|
} |
|
---- |
|
|
|
Kotlin:: |
|
+ |
|
[source,kotlin,role="secondary"] |
|
---- |
|
@Bean |
|
fun webFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain { |
|
return http { |
|
// ... |
|
headers { |
|
cache { |
|
disable() |
|
} |
|
} |
|
} |
|
} |
|
---- |
|
====== |
|
|
|
|
|
[[webflux-headers-content-type-options]] |
|
== Content Type Options |
|
By default, Spring Security includes xref:features/exploits/headers.adoc#headers-content-type-options[Content-Type] headers. |
|
However, you can disable it: |
|
|
|
.Content Type Options Disabled |
|
[tabs] |
|
====== |
|
Java:: |
|
+ |
|
[source,java,role="primary"] |
|
---- |
|
@Bean |
|
SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) { |
|
http |
|
// ... |
|
.headers((headers) -> headers |
|
.contentTypeOptions((contentTypeOptions) -> contentTypeOptions.disable()) |
|
); |
|
return http.build(); |
|
} |
|
---- |
|
|
|
Kotlin:: |
|
+ |
|
[source,kotlin,role="secondary"] |
|
---- |
|
@Bean |
|
fun webFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain { |
|
return http { |
|
// ... |
|
headers { |
|
contentTypeOptions { |
|
disable() |
|
} |
|
} |
|
} |
|
} |
|
---- |
|
====== |
|
|
|
[[webflux-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 customize the results explicitly. |
|
For example, the following example explicitly provides HSTS: |
|
|
|
.Strict Transport Security |
|
[tabs] |
|
====== |
|
Java:: |
|
+ |
|
[source,java,role="primary"] |
|
---- |
|
@Bean |
|
SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) { |
|
http |
|
// ... |
|
.headers((headers) -> headers |
|
.hsts((hsts) -> hsts |
|
.includeSubdomains(true) |
|
.preload(true) |
|
.maxAge(Duration.ofDays(365)) |
|
) |
|
); |
|
return http.build(); |
|
} |
|
---- |
|
|
|
Kotlin:: |
|
+ |
|
[source,kotlin,role="secondary"] |
|
---- |
|
@Bean |
|
fun webFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain { |
|
return http { |
|
// ... |
|
headers { |
|
hsts { |
|
includeSubdomains = true |
|
preload = true |
|
maxAge = Duration.ofDays(365) |
|
} |
|
} |
|
} |
|
} |
|
---- |
|
====== |
|
|
|
[[webflux-headers-frame-options]] |
|
== X-Frame-Options |
|
By default, Spring Security disables rendering within an iframe by using xref:features/exploits/headers.adoc#headers-frame-options[`X-Frame-Options`]. |
|
|
|
You can customize frame options to use the same origin: |
|
|
|
.X-Frame-Options: SAMEORIGIN |
|
[tabs] |
|
====== |
|
Java:: |
|
+ |
|
[source,java,role="primary"] |
|
---- |
|
@Bean |
|
SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) { |
|
http |
|
// ... |
|
.headers((headers) -> headers |
|
.frameOptions((frameOptions) -> frameOptions |
|
.mode(SAMEORIGIN) |
|
) |
|
); |
|
return http.build(); |
|
} |
|
---- |
|
|
|
Kotlin:: |
|
+ |
|
[source,kotlin,role="secondary"] |
|
---- |
|
@Bean |
|
fun webFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain { |
|
return http { |
|
// ... |
|
headers { |
|
frameOptions { |
|
mode = SAMEORIGIN |
|
} |
|
} |
|
} |
|
} |
|
---- |
|
====== |
|
|
|
[[webflux-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>. |
|
You can disable the `X-XSS-Protection` header entirely: |
|
|
|
.X-XSS-Protection Customization |
|
[tabs] |
|
====== |
|
Java:: |
|
+ |
|
[source,java,role="primary"] |
|
---- |
|
@Bean |
|
SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) { |
|
http |
|
// ... |
|
.headers((headers) -> headers |
|
.xssProtection((xssProtection) -> xssProtection.disable()) |
|
); |
|
return http.build(); |
|
} |
|
---- |
|
|
|
Kotlin:: |
|
+ |
|
[source,kotlin,role="secondary"] |
|
---- |
|
@Bean |
|
fun webFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain { |
|
return http { |
|
// ... |
|
headers { |
|
xssProtection { |
|
disable() |
|
} |
|
} |
|
} |
|
} |
|
---- |
|
====== |
|
|
|
You can also change the header value: |
|
|
|
.X-XSS-Protection Explicit header value |
|
[tabs] |
|
====== |
|
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]] |
|
== 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. |
|
The web application author must declare the security policies to enforce and/or monitor for the protected resources. |
|
|
|
For example, 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 policy, you can enable the CSP header: |
|
|
|
.Content Security Policy |
|
[tabs] |
|
====== |
|
Java:: |
|
+ |
|
[source,java,role="primary"] |
|
---- |
|
@Bean |
|
SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) { |
|
http |
|
// ... |
|
.headers((headers) -> headers |
|
.contentSecurityPolicy((policy) -> policy |
|
.policyDirectives("script-src 'self' https://trustedscripts.example.com; object-src https://trustedplugins.example.com; report-uri /csp-report-endpoint/") |
|
) |
|
); |
|
return http.build(); |
|
} |
|
---- |
|
|
|
Kotlin:: |
|
+ |
|
[source,kotlin,role="secondary"] |
|
---- |
|
@Bean |
|
fun webFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain { |
|
return http { |
|
// ... |
|
headers { |
|
contentSecurityPolicy { |
|
policyDirectives = "script-src 'self' https://trustedscripts.example.com; object-src https://trustedplugins.example.com; report-uri /csp-report-endpoint/" |
|
} |
|
} |
|
} |
|
} |
|
---- |
|
====== |
|
|
|
To enable the CSP `report-only` header, provide the following configuration: |
|
|
|
.Content Security Policy Report Only |
|
[tabs] |
|
====== |
|
Java:: |
|
+ |
|
[source,java,role="primary"] |
|
---- |
|
@Bean |
|
SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) { |
|
http |
|
// ... |
|
.headers((headers) -> headers |
|
.contentSecurityPolicy((policy) -> policy |
|
.policyDirectives("script-src 'self' https://trustedscripts.example.com; object-src https://trustedplugins.example.com; report-uri /csp-report-endpoint/") |
|
.reportOnly() |
|
) |
|
); |
|
return http.build(); |
|
} |
|
---- |
|
|
|
Kotlin:: |
|
+ |
|
[source,kotlin,role="secondary"] |
|
---- |
|
@Bean |
|
fun webFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain { |
|
return http { |
|
// ... |
|
headers { |
|
contentSecurityPolicy { |
|
policyDirectives = "script-src 'self' https://trustedscripts.example.com; object-src https://trustedplugins.example.com; report-uri /csp-report-endpoint/" |
|
reportOnly = true |
|
} |
|
} |
|
} |
|
} |
|
---- |
|
====== |
|
|
|
[[webflux-headers-referrer]] |
|
== Referrer Policy |
|
|
|
Spring Security adds the xref:features/exploits/headers.adoc#headers-referrer[Referrer Policy] header by default with the directive `no-referrer`. |
|
You can change the Referrer Policy header using configuration as shown below: |
|
|
|
.Referrer Policy Configuration |
|
[tabs] |
|
====== |
|
Java:: |
|
+ |
|
[source,java,role="primary"] |
|
---- |
|
@Bean |
|
SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) { |
|
http |
|
// ... |
|
.headers((headers) -> headers |
|
.referrerPolicy((referrer) -> referrer |
|
.policy(ReferrerPolicy.SAME_ORIGIN) |
|
) |
|
); |
|
return http.build(); |
|
} |
|
---- |
|
|
|
Kotlin:: |
|
+ |
|
[source,kotlin,role="secondary"] |
|
---- |
|
@Bean |
|
fun webFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain { |
|
return http { |
|
// ... |
|
headers { |
|
referrerPolicy { |
|
policy = ReferrerPolicy.SAME_ORIGIN |
|
} |
|
} |
|
} |
|
} |
|
---- |
|
====== |
|
|
|
|
|
[[webflux-headers-feature]] |
|
== Feature Policy |
|
|
|
By default, Spring Security does not add xref:features/exploits/headers.adoc#headers-feature[Feature Policy] headers. |
|
Consider the following `Feature-Policy` header: |
|
|
|
.Feature-Policy Example |
|
[source] |
|
---- |
|
Feature-Policy: geolocation 'self' |
|
---- |
|
|
|
You can enable the preceding Feature Policy header: |
|
|
|
.Feature-Policy Configuration |
|
[tabs] |
|
====== |
|
Java:: |
|
+ |
|
[source,java,role="primary"] |
|
---- |
|
@Bean |
|
SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) { |
|
http |
|
// ... |
|
.headers((headers) -> headers |
|
.featurePolicy("geolocation 'self'") |
|
); |
|
return http.build(); |
|
} |
|
---- |
|
|
|
Kotlin:: |
|
+ |
|
[source,kotlin,role="secondary"] |
|
---- |
|
@Bean |
|
fun webFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain { |
|
return http { |
|
// ... |
|
headers { |
|
featurePolicy("geolocation 'self'") |
|
} |
|
} |
|
} |
|
---- |
|
====== |
|
|
|
|
|
[[webflux-headers-permissions]] |
|
== Permissions Policy |
|
|
|
By default, Spring Security does not add xref:features/exploits/headers.adoc#headers-permissions[Permissions Policy] headers. |
|
Consider the following `Permissions-Policy` header: |
|
|
|
.Permissions-Policy Example |
|
[source] |
|
---- |
|
Permissions-Policy: geolocation=(self) |
|
---- |
|
|
|
You can enable the preceding Permissions Policy header: |
|
|
|
.Permissions-Policy Configuration |
|
[tabs] |
|
====== |
|
Java:: |
|
+ |
|
[source,java,role="primary"] |
|
---- |
|
@Bean |
|
SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) { |
|
http |
|
// ... |
|
.headers((headers) -> headers |
|
.permissionsPolicy((permissions) -> permissions |
|
.policy("geolocation=(self)") |
|
) |
|
); |
|
return http.build(); |
|
} |
|
---- |
|
|
|
Kotlin:: |
|
+ |
|
[source,kotlin,role="secondary"] |
|
---- |
|
@Bean |
|
fun webFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain { |
|
return http { |
|
// ... |
|
headers { |
|
permissionsPolicy { |
|
policy = "geolocation=(self)" |
|
} |
|
} |
|
} |
|
} |
|
---- |
|
====== |
|
|
|
|
|
[[webflux-headers-clear-site-data]] |
|
== Clear Site Data |
|
|
|
By default, Spring Security does not add xref:features/exploits/headers.adoc#headers-clear-site-data[Clear-Site-Data] headers. |
|
Consider the following `Clear-Site-Data` header: |
|
|
|
.Clear-Site-Data Example |
|
---- |
|
Clear-Site-Data: "cache", "cookies" |
|
---- |
|
|
|
You can send the `Clear-Site-Data` header on logout: |
|
|
|
.Clear-Site-Data Configuration |
|
[tabs] |
|
====== |
|
Java:: |
|
+ |
|
[source,java,role="primary"] |
|
---- |
|
@Bean |
|
SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) { |
|
ServerLogoutHandler securityContext = new SecurityContextServerLogoutHandler(); |
|
ClearSiteDataServerHttpHeadersWriter writer = new ClearSiteDataServerHttpHeadersWriter(CACHE, COOKIES); |
|
ServerLogoutHandler clearSiteData = new HeaderWriterServerLogoutHandler(writer); |
|
DelegatingServerLogoutHandler logoutHandler = new DelegatingServerLogoutHandler(securityContext, clearSiteData); |
|
|
|
http |
|
// ... |
|
.logout() |
|
.logoutHandler(logoutHandler); |
|
return http.build(); |
|
} |
|
---- |
|
|
|
Kotlin:: |
|
+ |
|
[source,kotlin,role="secondary"] |
|
---- |
|
@Bean |
|
fun webFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain { |
|
val securityContext: ServerLogoutHandler = SecurityContextServerLogoutHandler() |
|
val writer = ClearSiteDataServerHttpHeadersWriter(CACHE, COOKIES) |
|
val clearSiteData: ServerLogoutHandler = HeaderWriterServerLogoutHandler(writer) |
|
val customLogoutHandler = DelegatingServerLogoutHandler(securityContext, clearSiteData) |
|
|
|
return http { |
|
// ... |
|
logout { |
|
logoutHandler = customLogoutHandler |
|
} |
|
} |
|
} |
|
---- |
|
======
|
|
|