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.
580 lines
14 KiB
580 lines
14 KiB
[[webflux-headers]] |
|
= Security HTTP Response Headers |
|
|
|
xref:overview/features/exploits/headers.adoc#headers[Security HTTP Response Headers] can be used 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:overview/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 utilize the headers, so additional testing is encouraged. |
|
|
|
You can customize specific headers. |
|
For example, assume that you want the defaults except you wish to specify `SAMEORIGIN` for xref:servlet/exploits/headers.adoc#servlet-headers-frame-options[X-Frame-Options]. |
|
|
|
You can easily do this with the following Configuration: |
|
|
|
.Customize Default Security Headers |
|
==== |
|
.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. |
|
An example is provided below: |
|
|
|
.Disable HTTP Security Response Headers |
|
==== |
|
.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:overview/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 things like CSS, JavaScript, and images are properly cached. |
|
|
|
When using Spring WebFlux, this is typically done within your configuration. |
|
Details on how to do this can be found 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 |
|
==== |
|
.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 |
|
Spring Security includes xref:overview/features/exploits/headers.adoc#headers-content-type-options[Content-Type] headers by default. |
|
However, you can disable it with: |
|
|
|
.Content Type Options Disabled |
|
==== |
|
.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) |
|
Spring Security provides the xref:overview/features/exploits/headers.adoc#headers-hsts[Strict Transport Security] header by default. |
|
However, you can customize the results explicitly. |
|
For example, the following is an example of explicitly providing HSTS: |
|
|
|
.Strict Transport Security |
|
==== |
|
.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 using xref:overview/features/exploits/headers.adoc#headers-frame-options[X-Frame-Options]. |
|
|
|
You can customize frame options to use the same origin using the following: |
|
|
|
.X-Frame-Options: SAMEORIGIN |
|
==== |
|
.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 block reflected XSS attacks using the <<headers-xss-protection,X-XSS-Protection header>. |
|
You can disable `X-XSS-Protection` with the following Configuration: |
|
|
|
.X-XSS-Protection Customization |
|
==== |
|
.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() |
|
} |
|
} |
|
} |
|
} |
|
---- |
|
==== |
|
|
|
[[webflux-headers-csp]] |
|
== Content Security Policy (CSP) |
|
Spring Security does not add xref:overview/features/exploits/headers.adoc#headers-csp[Content Security Policy] by default, because a reasonable default is impossible to know without context of the application. |
|
The web application author must declare the security policy(s) to enforce and/or monitor for the protected resources. |
|
|
|
For example, given 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/ |
|
---- |
|
==== |
|
|
|
You can enable the CSP header as shown below: |
|
|
|
.Content Security Policy |
|
==== |
|
.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 |
|
==== |
|
.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 does not add xref:overview/features/exploits/headers.adoc#headers-referrer[Referrer Policy] headers by default. |
|
You can enable the Referrer Policy header using configuration as shown below: |
|
|
|
.Referrer Policy Configuration |
|
==== |
|
.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 |
|
|
|
Spring Security does not add xref:overview/features/exploits/headers.adoc#headers-feature[Feature Policy] headers by default. |
|
The following `Feature-Policy` header: |
|
|
|
.Feature-Policy Example |
|
==== |
|
[source] |
|
---- |
|
Feature-Policy: geolocation 'self' |
|
---- |
|
==== |
|
|
|
You can enable the Feature Policy header as shown below: |
|
|
|
.Feature-Policy Configuration |
|
==== |
|
.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 |
|
|
|
Spring Security does not add xref:overview/features/exploits/headers.adoc#headers-permissions[Permissions Policy] headers by default. |
|
The following `Permissions-Policy` header: |
|
|
|
.Permissions-Policy Example |
|
==== |
|
[source] |
|
---- |
|
Permissions-Policy: geolocation=(self) |
|
---- |
|
==== |
|
|
|
You can enable the Permissions Policy header as shown below: |
|
|
|
.Permissions-Policy Configuration |
|
==== |
|
.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 |
|
|
|
Spring Security does not add xref:overview/features/exploits/headers.adoc#headers-clear-site-data[Clear-Site-Data] headers by default. |
|
The following Clear-Site-Data header: |
|
|
|
.Clear-Site-Data Example |
|
==== |
|
---- |
|
Clear-Site-Data: "cache", "cookies" |
|
---- |
|
==== |
|
|
|
can be sent on log out with the following configuration: |
|
|
|
.Clear-Site-Data Configuration |
|
==== |
|
.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 |
|
} |
|
} |
|
} |
|
---- |
|
====
|
|
|