diff --git a/config/src/main/java/org/springframework/security/config/web/server/ServerHttpSecurity.java b/config/src/main/java/org/springframework/security/config/web/server/ServerHttpSecurity.java index b6e66ab0eb..3d6ad7db22 100644 --- a/config/src/main/java/org/springframework/security/config/web/server/ServerHttpSecurity.java +++ b/config/src/main/java/org/springframework/security/config/web/server/ServerHttpSecurity.java @@ -2057,6 +2057,15 @@ public class ServerHttpSecurity { return new FeaturePolicySpec(policyDirectives); } + /** + * Configures {@code Referrer-Policy} response header. + * @param referrerPolicy the policy to use + * @return the {@link ReferrerPolicySpec} to configure + */ + public HeaderSpec referrerPolicy(ReferrerPolicy referrerPolicy) { + return referrerPolicy().referrerPolicy(referrerPolicy); + } + /** * Configures {@code Referrer-Policy} response header. * @return the {@link ReferrerPolicySpec} to configure @@ -2108,18 +2117,18 @@ public class ServerHttpSecurity { * The mode to configure. Default is * {@link org.springframework.security.web.server.header.XFrameOptionsServerHttpHeadersWriter.Mode#DENY} * @param mode the mode to use - * @return the {@link FrameOptionsSpec} to configure + * @return the {@link HeaderSpec} to configure */ - public FrameOptionsSpec mode(XFrameOptionsServerHttpHeadersWriter.Mode mode) { + public HeaderSpec mode(XFrameOptionsServerHttpHeadersWriter.Mode mode) { HeaderSpec.this.frameOptions.setMode(mode); - return this; + return and(); } /** * Allows method chaining to continue configuring the {@link ServerHttpSecurity} * @return the {@link HeaderSpec} to continue configuring */ - public HeaderSpec and() { + private HeaderSpec and() { return HeaderSpec.this; } @@ -2129,7 +2138,7 @@ public class ServerHttpSecurity { */ public HeaderSpec disable() { HeaderSpec.this.writers.remove(HeaderSpec.this.frameOptions); - return HeaderSpec.this; + return and(); } private FrameOptionsSpec() {} diff --git a/docs/manual/src/docs/asciidoc/_includes/reactive/headers.adoc b/docs/manual/src/docs/asciidoc/_includes/reactive/headers.adoc new file mode 100644 index 0000000000..c19bbdc6bd --- /dev/null +++ b/docs/manual/src/docs/asciidoc/_includes/reactive/headers.adoc @@ -0,0 +1,444 @@ + +[[webflux-headers]] +== Security HTTP Response Headers +This section discusses Spring Security's support for adding various security headers to the response of WebFlux. + +=== Default Security Headers +Spring Security allows users to easily inject the default security headers to assist in protecting their application. +The default for Spring Security is to include the following headers: + +[source,http] +---- +Cache-Control: no-cache, no-store, max-age=0, must-revalidate +Pragma: no-cache +Expires: 0 +X-Content-Type-Options: nosniff +Strict-Transport-Security: max-age=31536000 ; includeSubDomains +X-Frame-Options: DENY +X-XSS-Protection: 1; mode=block +---- + +NOTE: Strict-Transport-Security is only added on HTTPS requests + +For additional details on each of these headers, refer to the corresponding sections: + +* <> +* <> +* <> +* <> +* <> + +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 want your HTTP response headers to look like the following: + +[source,http] +---- +Cache-Control: no-cache, no-store, max-age=0, must-revalidate +Pragma: no-cache +Expires: 0 +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-XSS-Protection: 1; mode=block +---- + +Specifically, you want all of the default headers with the following customizations: + +* <> to allow any request from same domain +* <> will not be added to the response + +You can easily do this with the following Java Configuration: + +[source,java] +---- +@Bean +SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) { + http + // ... + .headers() + .hsts().disable() + .frameOptions().mode(Mode.SAMEORIGIN); + 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. +An example for both Java and XML based configuration is provided below: + +If necessary, you can disable all of the HTTP Security response headers with the following Java Configuration: + +[source,java] +---- +@Bean +SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) { + http + // ... + .headers() + .disable(); + return http.build(); +} +---- + +[[webflux-headers-cache-control]] +==== Cache Control +In the past Spring Security required you to provide your own cache control for your web application. +This seemed reasonable at the time, but browser caches have evolved to include caches for secure connections as well. +This means that a user may view an authenticated page, log out, and then a malicious user can use the browser history to view the cached page. +To help mitigate this Spring Security has added cache control support which will insert the following headers into you response by default. + +[source] +---- +Cache-Control: no-cache, no-store, max-age=0, must-revalidate +Pragma: no-cache +Expires: 0 +---- + + +If you actually want to cache specific responses, your application can selectively set the cache control headers to override the header set by Spring Security. +This is useful to ensure things like CSS, JavaScript, and images are properly cached. + +You can also disable cache control using the following Java Configuration: + +[source,java] +---- +@Bean +SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) { + http + // ... + .headers() + .cache().disable(); + return http.build(); +} +---- + +[[webflux-headers-content-type-options]] +==== Content Type Options +Historically browsers, including Internet Explorer, would try to guess the content type of a request using http://en.wikipedia.org/wiki/Content_sniffing[content sniffing]. +This allowed browsers to improve the user experience by guessing the content type on resources that had not specified the content type. +For example, if a browser encountered a JavaScript file that did not have the content type specified, it would be able to guess the content type and then execute it. + +[NOTE] +==== +There are many additional things one should do (i.e. only display the document in a distinct domain, ensure Content-Type header is set, sanitize the document, etc) when allowing content to be uploaded. +However, these measures are out of the scope of what Spring Security provides. +It is also important to point out when disabling content sniffing, you must specify the content type in order for things to work properly. +==== + +The problem with content sniffing is that this allowed malicious users to use polyglots (i.e. a file that is valid as multiple content types) to execute XSS attacks. +For example, some sites may allow users to submit a valid postscript document to a website and view it. +A malicious user might create a http://webblaze.cs.berkeley.edu/papers/barth-caballero-song.pdf[postscript document that is also a valid JavaScript file] and execute a XSS attack with it. + +Content sniffing can be disabled by adding the following header to our response: + +[source] +---- +X-Content-Type-Options: nosniff +---- + +Just as with the cache control element, the nosniff directive is added by default. +However, if need to disable the header, the following may be used: + +[source,java] +---- +@Bean +SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) { + http + // ... + .headers() + .contentTypeOptions().disable(); + return http.build(); +} +---- + +[[webflux-headers-hsts]] +==== HTTP Strict Transport Security (HSTS) +When you type in your bank's website, do you enter mybank.example.com or do you enter https://mybank.example.com[]? +If you omit the https protocol, you are potentially vulnerable to http://en.wikipedia.org/wiki/Man-in-the-middle_attack[Man in the Middle attacks]. +Even if the website performs a redirect to https://mybank.example.com a malicious user could intercept the initial HTTP request and manipulate the response (i.e. redirect to https://mibank.example.com and steal their credentials). + +Many users omit the https protocol and this is why http://tools.ietf.org/html/rfc6797[HTTP Strict Transport Security (HSTS)] was created. +Once mybank.example.com is added as a http://tools.ietf.org/html/rfc6797#section-5.1[HSTS host], a browser can know ahead of time that any request to mybank.example.com should be interpreted as https://mybank.example.com. +This greatly reduces the possibility of a Man in the Middle attack occurring. + +[NOTE] +==== +In accordance with http://tools.ietf.org/html/rfc6797#section-7.2[RFC6797], the HSTS header is only injected into HTTPS responses. +In order for the browser to acknowledge the header, the browser must first trust the CA that signed the SSL certificate used to make the connection (not just the SSL certificate). +==== + +One way for a site to be marked as a HSTS host is to have the host preloaded into the browser. +Another is to add the "Strict-Transport-Security" header to the response. +For example the following would instruct the browser to treat the domain as an HSTS host for a year (there are approximately 31536000 seconds in a year): + +[source] +---- +Strict-Transport-Security: max-age=31536000 ; includeSubDomains +---- + +The optional includeSubDomains directive instructs Spring Security that subdomains (i.e. secure.mybank.example.com) should also be treated as an HSTS domain. + +As with the other headers, Spring Security adds HSTS by default. +You can customize HSTS headers with Java Configuration: + +[source,java] +---- +@Bean +SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) { + http + // ... + .headers() + .hsts() + .includeSubdomains(true) + .maxAge(Duration.ofDays(365)); + return http.build(); +} +---- + + +[[webflux-headers-frame-options]] +==== X-Frame-Options +Allowing your website to be added to a frame can be a security issue. +For example, using clever CSS styling users could be tricked into clicking on something that they were not intending (http://www.youtube.com/watch?v=3mk0RySeNsU[video demo]). +For example, a user that is logged into their bank might click a button that grants access to other users. +This sort of attack is known as http://en.wikipedia.org/wiki/Clickjacking[Clickjacking]. + +[NOTE] +==== +Another modern approach to dealing with clickjacking is to use <>. +==== + +There are a number ways to mitigate clickjacking attacks. +For example, to protect legacy browsers from clickjacking attacks you can use https://www.owasp.org/index.php/Clickjacking_Defense_Cheat_Sheet#Best-for-now_Legacy_Browser_Frame_Breaking_Script[frame breaking code]. +While not perfect, the frame breaking code is the best you can do for the legacy browsers. + +A more modern approach to address clickjacking is to use https://developer.mozilla.org/en-US/docs/HTTP/X-Frame-Options[X-Frame-Options] header: + +[source] +---- +X-Frame-Options: DENY +---- + +The X-Frame-Options response header instructs the browser to prevent any site with this header in the response from being rendered within a frame. +By default, Spring Security disables rendering within an iframe. + +You can customize X-Frame-Options with Java Configuration using the following: + +[source,java] +---- +@Bean +SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) { + http + // ... + .headers() + .frameOptions() + .mode(SAMEORIGIN); + return http.build(); +} +---- + +[[webflux-headers-xss-protection]] +==== X-XSS-Protection +Some browsers have built in support for filtering out https://www.owasp.org/index.php/Testing_for_Reflected_Cross_site_scripting_(OWASP-DV-001)[reflected XSS attacks]. +This is by no means foolproof, but does assist in XSS protection. + +The filtering is typically enabled by default, so adding the header typically just ensures it is enabled and instructs the browser what to do when a XSS attack is detected. +For example, the filter might try to change the content in the least invasive way to still render everything. +At times, this type of replacement can become a http://hackademix.net/2009/11/21/ies-xss-filter-creates-xss-vulnerabilities/[XSS vulnerability in itself]. +Instead, it is best to block the content rather than attempt to fix it. +To do this we can add the following header: + +[source] +---- +X-XSS-Protection: 1; mode=block +---- + +This header is included by default. +However, we can customize with Java Configuration with the following: + +[source,java] +---- +@Bean +SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) { + http + // ... + .headers() + .xssProtection() + .disable(); + return http.build(); +} +---- + +[[webflux-headers-csp]] +==== Content Security Policy (CSP) + +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). +CSP is a declarative policy that provides a facility for web application authors to declare and ultimately inform the client (user-agent) about the sources from which the web application expects to load resources. + +[NOTE] +==== +Content Security Policy is not intended to solve all content injection vulnerabilities. +Instead, CSP can be leveraged to help reduce the harm caused by content injection attacks. +As a first line of defense, web application authors should validate their input and encode their output. +==== + +A web application may employ the use of CSP by including one of the following HTTP headers in the response: + +* *_Content-Security-Policy_* +* *_Content-Security-Policy-Report-Only_* + +Each of these headers are used as a mechanism to deliver a *_security policy_* to the client. +A security policy contains a set of *_security policy directives_* (for example, _script-src_ and _object-src_), each responsible for declaring the restrictions for a particular resource representation. + +For example, a web application can declare that it expects to load scripts from specific, trusted sources, by including the following header in the response: + +[source] +---- +Content-Security-Policy: script-src https://trustedscripts.example.com +---- + +An attempt to load a script from another source other than what is declared in the _script-src_ directive will be blocked by the user-agent. +Additionally, if the https://www.w3.org/TR/CSP2/#directive-report-uri[*_report-uri_*] directive is declared in the security policy, then the violation will be reported by the user-agent to the declared URL. + +For example, if a web application violates the declared security policy, the following response header will instruct the user-agent to send violation reports to the URL specified in the policy's _report-uri_ directive. + +[source] +---- +Content-Security-Policy: script-src https://trustedscripts.example.com; report-uri /csp-report-endpoint/ +---- + +https://www.w3.org/TR/CSP2/#violation-reports[*_Violation reports_*] are standard JSON structures that can be captured either by the web application's own API or by a publicly hosted CSP violation reporting service, such as, https://report-uri.io/[*_REPORT-URI_*]. + +The *_Content-Security-Policy-Report-Only_* header provides the capability for web application authors and administrators to monitor security policies, rather than enforce them. +This header is typically used when experimenting and/or developing security policies for a site. +When a policy is deemed effective, it can be enforced by using the _Content-Security-Policy_ header field instead. + +Given the following response header, the policy declares that scripts may be loaded from one of two possible sources. + +[source] +---- +Content-Security-Policy-Report-Only: script-src 'self' https://trustedscripts.example.com; report-uri /csp-report-endpoint/ +---- + +If the site violates this policy, by attempting to load a script from _evil.com_, the user-agent will send a violation report to the declared URL specified by the _report-uri_ directive, but still allow the violating resource to load nevertheless. + +[[webflux-headers-csp-configure]] +===== Configuring Content Security Policy + +It's important to note that Spring Security *_does not add_* Content Security Policy by default. +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: + +[source] +---- +script-src 'self' https://trustedscripts.example.com; object-src https://trustedplugins.example.com; report-uri /csp-report-endpoint/ +---- + +You can enable the CSP header using Java configuration as shown below: + +[source,java] +---- +@Bean +SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) { + http + // ... + .headers() + .contentSecurityPolicy("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 Java configuration: + +[source,java] +---- +@Bean +SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) { + http + // ... + .headers() + .contentSecurityPolicy("script-src 'self' https://trustedscripts.example.com; object-src https://trustedplugins.example.com; report-uri /csp-report-endpoint/") + .reportOnly(); + return http.build(); +} +---- + +[[webflux-headers-csp-links]] +===== Additional Resources + +Applying Content Security Policy to a web application is often a non-trivial undertaking. +The following resources may provide further assistance in developing effective security policies for your site. + +http://www.html5rocks.com/en/tutorials/security/content-security-policy/[An Introduction to Content Security Policy] + +https://developer.mozilla.org/en-US/docs/Web/Security/CSP[CSP Guide - Mozilla Developer Network] + +https://www.w3.org/TR/CSP2/[W3C Candidate Recommendation] + +[[webflux-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. + +[[webflux-headers-referrer-configure]] +===== Configuring Referrer Policy + +Spring Security *_doesn't add_* Referrer Policy header by default. + +You can enable the Referrer-Policy header using Java configuration as shown below: + +[source,java] +---- +@Bean +SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) { + http + // ... + .headers() + .referrerPolicy(ReferrerPolicy.SAME_ORIGIN); + return http.build(); +} +---- + + +[[webflux-headers-feature]] +==== Feature Policy + +https://wicg.github.io/feature-policy/[Feature Policy] is a mechanism that allows web developers to selectively enable, disable, and modify the behavior of certain APIs and web features in the browser. + +[source] +---- +Feature-Policy: geolocation 'self' +---- + +With Feature Policy, developers can opt-in to a set of "policies" for the browser to enforce on specific features used throughout your site. +These policies restrict what APIs the site can access or modify the browser's default behavior for certain features. + +[[webflux-headers-feature-configure]] +===== Configuring Feature Policy + +Spring Security *_doesn't add_* Feature Policy header by default. + +You can enable the Feature-Policy header using Java configuration as shown below: + +[source,java] +---- +@Bean +SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) { + http + // ... + .headers() + .featurePolicy("geolocation 'self'"); + return http.build(); +} +---- diff --git a/docs/manual/src/docs/asciidoc/_includes/reactive/index.adoc b/docs/manual/src/docs/asciidoc/_includes/reactive/index.adoc index a5bbcda545..c385762cb2 100644 --- a/docs/manual/src/docs/asciidoc/_includes/reactive/index.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/reactive/index.adoc @@ -2,6 +2,8 @@ include::webflux.adoc[leveloffset=+1] +include::headers.adoc[leveloffset=+1] + include::oauth2/index.adoc[leveloffset=+1] include::registered-oauth2-authorized-client.adoc[leveloffset=+1]