// FIXME: Add links to Servlet and WebFlux support
[[csrf]]
= Cross Site Request Forgery (CSRF)
Spring provides comprehensive support for protecting against https://en.wikipedia.org/wiki/Cross-site_request_forgery[Cross Site Request Forgery (CSRF)] attacks.
In the following sections we will explore:
* <<csrf-explained>>
* <<csrf-protection>>
* <<csrf-considerations>>
// FIXME: Add WebFlux csrf documentation (the link below is broken)
[NOTE]
====
This portion of the documentation discusses the general topic of CSRF protection.
Refer to the relevant sections for specific information on CSRF protection for <<servlet-csrf,servlet>> and <<webflux-csrf,WebFlux>> based applications.
====
[[csrf-explained]]
== What is a CSRF Attack?
The best way to understand a CSRF attack is by taking a look at a concrete example.
Assume that your bank's website provides a form that allows transferring money from the currently logged in user to another bank account.
For example, the transfer form might look like:
.Transfer form
====
[source,html]
----
<form method="post"
action="/transfer">
<input type="text"
name="amount"/>
<input type="text"
name="routingNumber"/>
<input type="text"
name="account"/>
<input type="submit"
value="Transfer"/>
</form>
----
====
The corresponding HTTP request might look like:
.Transfer HTTP request
====
[source]
----
POST /transfer HTTP/1.1
Host: bank.example.com
Cookie: JSESSIONID=randomid
Content-Type: application/x-www-form-urlencoded
amount=100.00&routingNumber=1234&account=9876
----
====
Now pretend you authenticate to your bank's website and then, without logging out, visit an evil website.
The evil website contains an HTML page with the following form:
.Evil transfer form
====
[source,html]
----
<form method="post"
action="https://bank.example.com/transfer">
<input type="hidden"
name="amount"
value="100.00"/>
<input type="hidden"
name="routingNumber"
value="evilsRoutingNumber"/>
<input type="hidden"
name="account"
value="evilsAccountNumber"/>
<input type="submit"
value="Win Money!"/>
</form>
----
====
You like to win money, so you click on the submit button.
In the process, you have unintentionally transferred $100 to a malicious user.
This happens because, while the evil website cannot see your cookies, the cookies associated with your bank are still sent along with the request.
Worst yet, this whole process could have been automated using JavaScript.
This means you didn't even need to click on the button.
Furthermore, it could just as easily happen when visiting an honest site that is a victim of a https://www.owasp.org/index.php/Cross-site_Scripting_(XSS)[XSS attack].
So how do we protect our users from such attacks?
[[csrf-protection]]
== Protecting Against CSRF Attacks
The reason that a CSRF attack is possible is that the HTTP request from the victim's website and the request from the attacker's website are exactly the same.
This means there is no way to reject requests coming from the evil website and allow requests coming from the bank's website.
To protect against CSRF attacks we need to ensure there is something in the request that the evil site is unable to provide so we can differentiate the two requests.
Spring provides two mechanisms to protect against CSRF attacks:
* The <<Synchronizer Token Pattern>>
* Specifying the <<SameSite Attribute>> on your session cookie
[NOTE]
====
Both protections require require that <<Safe Methods Must be Idempotent>>
====
[[csrf-protection-idempotent]]
=== Safe Methods Must be Idempotent
In order for <<csrf-protection,either protection>> against CSRF to work, the application must ensure that https://tools.ietf.org/html/rfc7231#section-4.2.1["safe" HTTP methods are idempotent].
This means that requests with the HTTP method `GET`, `HEAD`, `OPTIONS`, and `TRACE` should not change the state of the application.
[[csrf-protection-stp]]
=== Synchronizer Token Pattern
The predominant and most comprehensive way to protect against CSRF attacks is to use the https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)_Prevention_Cheat_Sheet#General_Recommendation:_Synchronizer_Token_Pattern[Synchronizer Token Pattern].
This solution is to ensure that each HTTP request requires, in addition to our session cookie, a secure random generated value called a CSRF token must be present in the HTTP request.
When an HTTP request is submitted, the server must look up the expected CSRF token and compare it against the actual CSRF token in the HTTP request.
If the values do not match, the HTTP request should be rejected.
The key to this working is that the actual CSRF token should be in a part of the HTTP request that is not automatically included by the browser.
For example, requiring the actual CSRF token in an HTTP parameter or an HTTP header will protect against CSRF attacks.
Requiring the actual CSRF token in a cookie does not work because cookies are automatically included in the HTTP request by the browser.
We can relax the expectations to only require the actual CSRF token for each HTTP request that updates state of the application.
For that to work, our application must ensure that <<csrf-protection-idempotent,safe HTTP methods are idempotent>>.
This improves usability since we want to allow linking to our website using links from external sites.
Additionally, we do not want to include the random token in HTTP GET as this can cause the tokens to be leaked.
Let's take a look at how <<csrf-explained,our example>> would change when using the Synchronizer Token Pattern.
Assume the actual CSRF token is required to be in an HTTP parameter named `_csrf`.
Our application's transfer form would look like:
.Synchronizer Token Form
====
[source,html]
----
<form method="post"
action="/transfer">
<input type="hidden"
name="_csrf"
value="4bfd1575-3ad1-4d21-96c7-4ef2d9f86721"/>
<input type="text"
name="amount"/>
<input type="text"
name="routingNumber"/>
<input type="hidden"
name="account"/>
<input type="submit"
value="Transfer"/>
</form>
----
====
The form now contains a hidden input with the value of the CSRF token.
External sites cannot read the CSRF token since the same origin policy ensures the evil site cannot read the response.
The corresponding HTTP request to transfer money would look like this:
You will notice that the HTTP request now contains the `_csrf` parameter with a secure random value.
The evil website will not be able to provide the correct value for the `_csrf` parameter (which must be explicitly provided on the evil website) and the transfer will fail when the server compares the actual CSRF token to the expected CSRF token.
[[csrf-protection-ssa]]
=== SameSite Attribute
An emerging way to protect against <<csrf,CSRF Attacks>> is to specify the https://tools.ietf.org/html/draft-west-first-party-cookies[SameSite Attribute] on cookies.
A server can specify the `SameSite` attribute when setting a cookie to indicate that the cookie should not be sent when coming from external sites.
[NOTE]
====
Spring Security does not directly control the creation of the session cookie, so it does not provide support for the SameSite attribute.
https://spring.io/projects/spring-session[Spring Session] provides support for the `SameSite` attribute in servlet based applications.
Spring Framework's https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/server/session/CookieWebSessionIdResolver.html[CookieWebSessionIdResolver] provides out of the box support for the `SameSite` attribute in WebFlux based applications.
====
An example, HTTP response header with the `SameSite` attribute might look like:
* `Strict` - when specified any request coming from the https://tools.ietf.org/html/draft-west-first-party-cookies-07#section-2.1[same-site] will include the cookie.
Otherwise, the cookie will not be included in the HTTP request.
* `Lax` - when specified cookies will be sent when coming from the https://tools.ietf.org/html/draft-west-first-party-cookies-07#section-2.1[same-site] or when the request comes from top-level navigations and the <<Safe Methods Must be Idempotent,method is idempotent>>.
Otherwise, the cookie will not be included in the HTTP request.
Let's take a look at how <<csrf-explained,our example>> could be protected using the `SameSite` attribute.
The bank application can protect against CSRF by specifying the `SameSite` attribute on the session cookie.
With the `SameSite` attribute set on our session cookie, the browser will continue to send the `JSESSIONID` cookie with requests coming from the banking website.
However, the browser will no longer send the `JSESSIONID` cookie with a transfer request coming from the evil website.
Since the session is no longer present in the transfer request coming from the evil website, the application is protected from the CSRF attack.
There are some important https://tools.ietf.org/html/draft-west-first-party-cookies-07#section-5[considerations] that one should be aware about when using `SameSite` attribute to protect against CSRF attacks.
Setting the `SameSite` attribute to `Strict` provides a stronger defense but can confuse users.
Consider a user that stays logged into a social media site hosted at https://social.example.com.
The user receives an email at https://email.example.org that includes a link to the social media site.
If the user clicks on the link, they would rightfully expect to be authenticated to the social media site.
However, if the `SameSite` attribute is `Strict` the cookie would not be sent and so the user would not be authenticated.
[NOTE]
====
We could improve the protection and usability of `SameSite` protection against CSRF attacks by implementing https://github.com/spring-projects/spring-security/issues/7537[gh-7537].
====
Another obvious consideration is that in order for the `SameSite` attribute to protect users, the browser must support the `SameSite` attribute.
Most modern browsers do https://developer.mozilla.org/en-US/docs/Web/HTTP/headers/Set-Cookie#Browser_compatibility[support the SameSite attribute].
However, older browsers that are still in use may not.
For this reason, it is generally recommended to use the `SameSite` attribute as a defense in depth rather than the sole protection against CSRF attacks.
[[csrf-when]]
== When to use CSRF protection
When should you use CSRF protection?
Our recommendation is to use CSRF protection for any request that could be processed by a browser by normal users.
If you are only creating a service that is used by non-browser clients, you will likely want to disable CSRF protection.
[[csrf-when-json]]
=== CSRF protection and JSON
A common question is "do I need to protect JSON requests made by javascript?"
The short answer is, it depends.
However, you must be very careful as there are CSRF exploits that can impact JSON requests.
For example, a malicious user can create a http://blog.opensecurityresearch.com/2012/02/json-csrf-with-parameter-padding.html[CSRF with JSON using the following form]:
If an application were not validating the Content-Type, then it would be exposed to this exploit.
Depending on the setup, a Spring MVC application that validates the Content-Type could still be exploited by updating the URL suffix to end with `.json` as shown below:
In fact, if a user does not need to perform any actions in the web browser for a given request, they are likely still vulnerable to CSRF attacks.
For example, consider an application that uses a custom cookie that contains all the state within it for authentication instead of the JSESSIONID.
When the CSRF attack is made the custom cookie will be sent with the request in the same manner that the JSESSIONID cookie was sent in our previous example.
This application will be vulnerable to CSRF attacks.
Applications that use basic authentication are also vulnerable to CSRF attacks.
The application is vulnerable since the browser will automatically include the username and password in any requests in the same manner that the JSESSIONID cookie was sent in our previous example.
[[csrf-considerations]]
== CSRF Considerations
There are a few special considerations to consider when implementing protection against CSRF attacks.
// FIXME: Document rotating the CSRF token at log in to avoid a fixation attack
[[csrf-considerations-login]]
=== Logging In
In order to protect against https://en.wikipedia.org/wiki/Cross-site_request_forgery#Forging_login_requests[forging log in requests] the log in HTTP request should be protected against CSRF attacks.
Protecting against forging log in requests is necessary so that a malicious user cannot read a victim's sensitive information.
The attack is executed by:
* A malicious user performs a CSRF log in using the malicious user's credentials.
The victim is now authenticated as the malicious user.
* The malicious user then tricks the victim to visit the compromised website and enter sensitive information
* The information is associated to the malicious user's account so the malicious user can log in with their own credentials and view the vicitim's sensitive information
A possible complication to ensuring log in HTTP requests are protected against CSRF attacks is that the user might experience a session timeout that causes the request to be rejected.
A session timeout is surprising to users who do not expect to need to have a session in order to log in.
For more information refer to <<csrf-considerations-timeouts>>.
[[csrf-considerations-logout]]
=== Logging Out
In order to protect against forging log out requests, the log out HTTP request should be protected against CSRF attacks.
Protecting against forging log out requests is necessary so a malicious user cannot read a victim's sensitive information.
For details on the attack refer to https://labs.detectify.com/2017/03/15/loginlogout-csrf-time-to-reconsider/[this blog post].
A possible complication to ensuring log out HTTP requests are protected against CSRF attacks is that the user might experience a session timeout that causes the request to be rejected.
A session timeout is surprising to users who do not expect to need to have a session in order to log out.
For more information refer to <<csrf-considerations-timeouts>>.
[[csrf-considerations-timeouts]]
=== CSRF and Session Timeouts
More often than not, the expected CSRF token is stored in the session.
This means that as soon as the session expires the server will not find an expected CSRF token and reject the HTTP request.
There are a number of options to solve timeouts each of which come with trade offs.
* The best way to mitigate the timeout is by using JavaScript to request a CSRF token on form submission.
The form is then updated with the CSRF token and submitted.
* Another option is to have some JavaScript that lets the user know their session is about to expire.
The user can click a button to continue and refresh the session.
* Finally, the expected CSRF token could be stored in a cookie.
This allows the expected CSRF token to outlive the session.
+
One might ask why the expected CSRF token isn't stored in a cookie by default.
This is because there are known exploits in which headers (i.e. specify the cookies) can be set by another domain.
This is the same reason Ruby on Rails https://weblog.rubyonrails.org/2011/2/8/csrf-protection-bypass-in-ruby-on-rails/[no longer skips CSRF checks when the header X-Requested-With is present].
See http://lists.webappsec.org/pipermail/websecurity_lists.webappsec.org/2011-February/007533.html[this webappsec.org thread] for details on how to perform the exploit.
Another disadvantage is that by removing the state (i.e. the timeout) you lose the ability to forcibly terminate the token if it is compromised.
// FIXME: Document timeout with lengthy form expire. We do not want to automatically replay that request because it can lead to exploit
[[csrf-considerations-multipart]]
=== Multipart (file upload)
Protecting multipart requests (file uploads) from CSRF attacks causes a https://en.wikipedia.org/wiki/Chicken_or_the_egg[chicken and the egg] problem.
In order to prevent a CSRF attack from occurring, the body of the HTTP request must be read to obtain actual CSRF token.
However, reading the body means that the file will be uploaded which means an external site can upload a file.
There are two options to using CSRF protection with multipart/form-data.
Each option has its trade-offs.
* <<csrf-considerations-multipart-body,Place CSRF Token in the Body>>
* <<csrf-considerations-multipart-url,Place CSRF Token in the URL>>
[NOTE]
====
Before you integrate Spring Security's CSRF protection with multipart file upload, ensure that you can upload without the CSRF protection first.
More information about using multipart forms with Spring can be found within the https://docs.spring.io/spring/docs/5.2.x/spring-framework-reference/web.html#mvc-multipart[1.1.11. Multipart Resolver] section of the Spring reference and the https://docs.spring.io/spring/docs/5.2.x/javadoc-api/org/springframework/web/multipart/support/MultipartFilter.html[MultipartFilter javadoc].
====
[[csrf-considerations-multipart-body]]
==== Place CSRF Token in the Body
The first option is to include the actual CSRF token in the body of the request.
By placing the CSRF token in the body, the body will be read before authorization is performed.
This means that anyone can place temporary files on your server.
However, only authorized users will be able to submit a File that is processed by your application.
In general, this is the recommended approach because the temporary file uplaod should have a negligible impact on most servers.
[[csrf-considerations-multipart-url]]
==== Include CSRF Token in URL
If allowing unauthorized users to upload temporary files is not acceptable, an alternative is to include the expected CSRF token as a query parameter in the action attribute of the form.
The disadvantage to this approach is that query parameters can be leaked.
More generally, it is considered best practice to place sensitive data within the body or headers to ensure it is not leaked.
Additional information can be found in https://www.w3.org/Protocols/rfc2616/rfc2616-sec15.html#sec15.1.3[RFC 2616 Section 15.1.3 Encoding Sensitive Information in URI's].
[[csrf-considerations-override-method]]
==== HiddenHttpMethodFilter
In some applications a form parameter can be used to override the HTTP method.
For example, the form below could be used to treat the HTTP method as a `delete` rather than a `post`.
.CSRF Hidden HTTP Method Form
====
[source,html]
----
<form action="/process"
method="post">
<!-- ... -->
<input type="hidden"
name="_method"
value="delete"/>
</form>
----
====
Overriding the HTTP method occurs in a filter.
That filter must be placed before Spring Security's support.
Note that overriding only happens on a `post`, so this is actually unlikely to cause any real problems.
However, it is still best practice to ensure it is placed before Spring Security's filters.
In Spring's Servlet support, overriding the HTTP method is done using https://docs.spring.io/spring-framework/docs/5.2.x/javadoc-api/org/springframework/web/filter/reactive/HiddenHttpMethodFilter.html[HiddenHttpMethodFilter].
More information can be found in https://docs.spring.io/spring/docs/5.2.x/spring-framework-reference/web.html#mvc-rest-method-conversion[HTTP Method Conversion] section of the reference documentation.
In a Spring WebFlux application, overriding the HTTP method is done using https://docs.spring.io/spring-framework/docs/5.2.x/javadoc-api/org/springframework/web/filter/reactive/HiddenHttpMethodFilter.html[HiddenHttpMethodFilter].
You like to win money, so you click on the submit button.
In the process, you have unintentionally transferred $100 to a malicious user.
This happens because, while the evil website cannot see your cookies, the cookies associated with your bank are still sent along with the request.
Worst yet, this whole process could have been automated using JavaScript.
This means you didn't even need to click on the button.
So how do we protect ourselves from such attacks?
=== Synchronizer Token Pattern
The issue is that the HTTP request from the bank's website and the request from the evil website are exactly the same.
This means there is no way to reject requests coming from the evil website and allow requests coming from the bank's website.
To protect against CSRF attacks we need to ensure there is something in the request that the evil site is unable to provide.
One solution is to use the https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)_Prevention_Cheat_Sheet#General_Recommendation:_Synchronizer_Token_Pattern[Synchronizer Token Pattern].
This solution is to ensure that each request requires, in addition to our session cookie, a randomly generated token as an HTTP parameter.
When a request is submitted, the server must look up the expected value for the parameter and compare it against the actual value in the request.
If the values do not match, the request should fail.
We can relax the expectations to only require the token for each HTTP request that updates state.
This can be safely done since the same origin policy ensures the evil site cannot read the response.
Additionally, we do not want to include the random token in HTTP GET as this can cause the tokens to be leaked.
Let's take a look at how our example would change.
Assume the randomly generated token is present in an HTTP parameter named _csrf.
For example, the request to transfer money would look like this:
You will notice that we added the _csrf parameter with a random value.
Now the evil website will not be able to guess the correct value for the _csrf parameter (which must be explicitly provided on the evil website) and the transfer will fail when the server compares the actual token to the expected token.
=== When to use CSRF protection
When should you use CSRF protection? Our recommendation is to use CSRF protection for any request that could be processed by a browser by normal users.
If you are only creating a service that is used by non-browser clients, you will likely want to disable CSRF protection.
==== CSRF protection and JSON
A common question is "do I need to protect JSON requests made by javascript?" The short answer is, it depends.
However, you must be very careful as there are CSRF exploits that can impact JSON requests.
For example, a malicious user can create a http://blog.opensecurityresearch.com/2012/02/json-csrf-with-parameter-padding.html[CSRF with JSON using the following form]:
If an application were not validating the Content-Type, then it would be exposed to this exploit.
Depending on the setup, a Spring MVC application that validates the Content-Type could still be exploited by updating the URL suffix to end with ".json" as shown below:
What if my application is stateless? That doesn't necessarily mean you are protected.
In fact, if a user does not need to perform any actions in the web browser for a given request, they are likely still vulnerable to CSRF attacks.
For example, consider an application uses a custom cookie that contains all the state within it for authentication instead of the JSESSIONID.
When the CSRF attack is made the custom cookie will be sent with the request in the same manner that the JSESSIONID cookie was sent in our previous example.
Users using basic authentication are also vulnerable to CSRF attacks since the browser will automatically include the username password in any requests in the same manner that the JSESSIONID cookie was sent in our previous example.
[[csrf-using]]
=== Using Spring Security CSRF Protection
So what are the steps necessary to use Spring Security's to protect our site against CSRF attacks? The steps to using Spring Security's CSRF protection are outlined below:
* <<csrf-use-proper-verbs,Use proper HTTP verbs>>
* <<csrf-configure,Configure CSRF Protection>>
* <<csrf-include-csrf-token,Include the CSRF Token>>
[[csrf-use-proper-verbs]]
==== Use proper HTTP verbs
[[servlet-csrf-idempotent]]
=== Use proper HTTP verbs
The first step to protecting against CSRF attacks is to ensure your website uses proper HTTP verbs.
Specifically, before Spring Security's CSRF support can be of use, you need to be certain that your application is using PATCH, POST, PUT, and/or DELETE for anything that modifies state.
This is covered in detail in <<csrf-protection-idempotent,Safe Methods Must be Idempotent>>.
This is not a limitation of Spring Security's support, but instead a general requirement for proper CSRF prevention.
The reason is that including private information in an HTTP GET can cause the information to be leaked.
See https://www.w3.org/Protocols/rfc2616/rfc2616-sec15.html#sec15.1.3[RFC 2616 Section 15.1.3 Encoding Sensitive Information in URI's] for general guidance on using POST instead of GET for sensitive information.
[[servlet-csrf-configure]]
=== Configure CSRF Protection
The next step is to configure Spring Security's CSRF protection within your application.
Spring Security's CSRF protection is enabled by default, but you may need to customize the configuration.
Below are a few common customizations.
[[servlet-csrf-configure-custom-repository]]
==== Custom CsrfTokenRepository
By default Spring Security stores the expected CSRF token in the `HttpSession` using `HttpSessionCsrfTokenRepository`.
There can be cases where users will want to configure a custom `CsrfTokenRepository`.
For example, it might be desirable to persist the `CsrfToken` in a cookie to <<servlet-csrf-include-ajax-auto,support a JavaScript based application>>.
By default the `CookieCsrfTokenRepository` will write to a cookie named `XSRF-TOKEN` and read it from a header named `X-XSRF-TOKEN` or the HTTP parameter `_csrf`.
These defaults come from https://docs.angularjs.org/api/ng/service/$http#cross-site-request-forgery-xsrf-protection[AngularJS]
You can configure `CookieCsrfTokenRepository` in XML using the following:
[[csrf-configure]]
==== Configure CSRF Protection
The next step is to include Spring Security's CSRF protection within your application.
Some frameworks handle invalid CSRF tokens by invaliding the user's session, but this causes <<csrf-logout,its own problems>>.
Instead by default Spring Security's CSRF protection will produce an HTTP 403 access denied.
This can be customized by configuring the <<access-denied-handler,AccessDeniedHandler>> to process `InvalidCsrfTokenException` differently.
As of Spring Security 4.0, CSRF protection is enabled by default with XML configuration.
If you would like to disable CSRF protection, the corresponding XML configuration can be seen below.
.Store CSRF Token in a Cookie with XML Configuration
The sample explicitly sets `cookieHttpOnly=false`.
This is necessary to allow JavaScript (i.e. AngularJS) to read it.
If you do not need the ability to read the cookie with JavaScript directly, it is recommended to omit `cookieHttpOnly=false` (by using `new CookieCsrfTokenRepository()` instead) to improve security.
====
[[servlet-csrf-configure-disable]]
==== Disable CSRF Protection
CSRF protection is enabled by default.
However, it is simple to disable CSRF protection if it <<csrf-when,makes sense for your application>>.
The XML configuration below will disable CSRF protection.
.Disable CSRF XML Configuration
====
[source,xml]
----
<http>
<!-- ... -->
<csrf disabled="true"/>
</http>
----
====
The Java configuration below will disable CSRF protection.
In order for the <<csrf-protection-stp,synchronizer token pattern>> to protect against CSRF attacks, we must include the actual CSRF token in the HTTP request.
This must be included in a part of the request (i.e. form parameter, HTTP header, etc) that is not automatically included in the HTTP request by the browser.
Spring Security's https://docs.spring.io/spring-security/site/docs/current/api/org/springframework/security/web/csrf/CsrfFilter.html[CsrfFilter] exposes a https://docs.spring.io/spring-security/site/docs/current/api/org/springframework/security/web/csrf/CsrfToken.html[CsrfToken] as an `HttpServletRequest` attribute named `_csrf`.
This means that any view technology can access the `CsrfToken` to expose the expected token as either a <<servlet-csrf-include-form-attr,form>> or <<servlet-csrf-include-ajax-meta-attr,meta tag>>.
Fortunately, there are integrations listed below that make including the token in <<servlet-csrf-include-form,form>> and <<servlet-csrf-include-ajax,ajax>> requests even easier.
[[servlet-csrf-include-form]]
==== Form URL Encoded
In order to post an HTML form the CSRF token must be included in the form as a hidden input.
For example, the rendered HTML might look like:
.CSRF Token HTML
====
[source,html]
----
<input type="hidden"
name="_csrf"
value="4bfd1575-3ad1-4d21-96c7-4ef2d9f86721"/>
----
====
Next we will discuss various ways of including the CSRF token in a form as a hidden input.
[[servlet-csrf-include-form-auto]]
===== Automatic CSRF Token Inclusion
Spring Security's CSRF support provides integration with Spring's https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/servlet/support/RequestDataValueProcessor.html[RequestDataValueProcessor] via its https://docs.spring.io/spring-security/site/docs/current/api/org/springframework/security/web/servlet/support/csrf/CsrfRequestDataValueProcessor.html[CsrfRequestDataValueProcessor].
This means that if you leverage https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html#mvc-view-jsp-formtaglib[Spring’s form tag library], https://www.thymeleaf.org/doc/tutorials/2.1/thymeleafspring.html#integration-with-requestdatavalueprocessor[Thymleaf], or any other view technology that integrates with `RequestDataValueProcessor`, then forms that have an unsafe HTTP method (i.e. post) will automatically include the actual CSRF token.
[[servlet-csrf-include-form-tag]]
===== csrfInput Tag
If you are using JSPs, then you can use https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html#mvc-view-jsp-formtaglib[Spring’s form tag library].
However, if that is not an option, you can also easily include the token with the <<taglibs-csrfinput,csrfInput>> tag.
[[servlet-csrf-include-form-attr]]
===== CsrfToken Request Attribute
If the <<servlet-csrf-include,other options>> for including the actual CSRF token in the request do not work, you can take advantage of the fact that the `CsrfToken` <<servlet-csrf-include,is exposed>> as an `HttpServletRequest` attribute named `_csrf`.
[[csrf-include-csrf-token-form]]
===== Form Submissions
The last step is to ensure that you include the CSRF token in all PATCH, POST, PUT, and DELETE methods.
One way to approach this is to use the `_csrf` request attribute to obtain the current `CsrfToken`.
An example of doing this with a JSP is shown below:
.CSRF Token in Form with Request Attribute
====
[source,xml]
----
<c:url var="logoutUrl" value="/logout"/>
@ -214,39 +187,46 @@ An example of doing this with a JSP is shown below:
value="${_csrf.token}"/>
</form>
----
An easier approach is to use <<the-csrfinput-tag,the csrfInput tag>> from the Spring Security JSP tag library.
[NOTE]
====
If you are using Spring MVC `<form:form>` tag or https://www.thymeleaf.org/whatsnew21.html#reqdata[Thymeleaf 2.1+] and are using `@EnableWebSecurity`, the `CsrfToken` is automatically included for you (using the `CsrfRequestDataValueProcessor`).
====
[[csrf-include-csrf-token-ajax]]
===== Ajax and JSON Requests
[[servlet-csrf-include-ajax]]
==== Ajax and JSON Requests
If you are using JSON, then it is not possible to submit the CSRF token within an HTTP parameter.
Instead you can submit the token within a HTTP header.
A typical pattern would be to include the CSRF token within your meta tags.
An example with a JSP is shown below:
In the following sections we will discuss various ways of including the CSRF token as an HTTP request header in JavaScript based applications.
[source,xml]
[[servlet-csrf-include-ajax-auto]]
===== Automatic Inclusion
Spring Security can easily be <<servlet-csrf-configure-custom-repository,configured>> to store the expected CSRF token in a cookie.
By storing the expected CSRF in a cookie, JavaScript frameworks like https://docs.angularjs.org/api/ng/service/$http#cross-site-request-forgery-xsrf-protection[AngularJS] will automatically include the actual CSRF token in the HTTP request headers.
[[servlet-csrf-include-ajax-meta]]
===== Meta tags
An alternative pattern to <<servlet-csrf-include-form-attr-auto,exposing the CSRF in a cookie>> is to include the CSRF token within your `meta` tags.
Instead of manually creating the meta tags, you can use the simpler <<the-csrfmetatags-tag,csrfMetaTags tag>> from the Spring Security JSP tag library.
You can then include the token within all your Ajax requests.
Once the meta tags contained the CSRF token, the JavaScript code would read the meta tags and include the CSRF token as a header.
If you were using jQuery, this could be done with the following:
As an alternative to jQuery, we recommend using https://github.com/cujojs[cujoJS's] rest.js.
The https://github.com/cujojs/rest[rest.js] module provides advanced support for working with HTTP requests and responses in RESTful ways.
A core capability is the ability to contextualize the HTTP client adding behavior as needed by chaining interceptors on to the client.
[[servlet-csrf-include-ajax-meta-tag]]
====== csrfMeta tag
[source,javascript]
If you are using JSPs a simple way to write the CSRF token to the `meta` tags is by leveraging the <<taglibs-csrfmeta,csrfMeta>> tag.
[[servlet-csrf-include-ajax-meta-attr]]
====== CsrfToken Request Attribute
If the <<servlet-csrf-include,other options>> for including the actual CSRF token in the request do not work, you can take advantage of the fact that the `CsrfToken` <<servlet-csrf-include,is exposed>> as an `HttpServletRequest` attribute named `_csrf`.
An example of doing this with a JSP is shown below:
The configured client can be shared with any component of the application that needs to make a request to the CSRF protected resource.
One significant difference between rest.js and jQuery is that only requests made with the configured client will contain the CSRF token, vs jQuery where __all__ requests will include the token.
The ability to scope which requests receive the token helps guard against leaking the CSRF token to a third party.
Please refer to the https://github.com/cujojs/rest/tree/master/docs[rest.js reference documentation] for more information on rest.js.
[[csrf-cookie]]
===== CookieCsrfTokenRepository
There can be cases where users will want to persist the `CsrfToken` in a cookie.
By default the `CookieCsrfTokenRepository` will write to a cookie named `XSRF-TOKEN` and read it from a header named `X-XSRF-TOKEN` or the HTTP parameter `_csrf`.
These defaults come from https://docs.angularjs.org/api/ng/service/$http#cross-site-request-forgery-xsrf-protection[AngularJS]
You can configure `CookieCsrfTokenRepository` in XML using the following:
The sample explicitly sets `cookieHttpOnly=false`.
This is necessary to allow JavaScript (i.e. AngularJS) to read it.
If you do not need the ability to read the cookie with JavaScript directly, it is recommended to omit `cookieHttpOnly=false` (by using `new CookieCsrfTokenRepository()` instead) to improve security.
====
[[servlet-csrf-considerations]]
== CSRF Considerations
There are a few special considerations to consider when implementing protection against CSRF attacks.
This section discusses those considerations as it pertains to servlet environments.
Refer to <<csrf-considerations>> for a more general discussion.
[[csrf-caveats]]
=== CSRF Caveats
There are a few caveats when implementing CSRF.
[[servlet-considerations-csrf-login]]
=== Logging In
It is important to <<csrf-considerations-login,require CSRF for log in>> requests to protect against forging log in attempts.
Spring Security's servlet support does this out of the box.
[[csrf-timeouts]]
==== Timeouts
One issue is that the expected CSRF token is stored in the HttpSession, so as soon as the HttpSession expires your configured `AccessDeniedHandler` will receive a InvalidCsrfTokenException.
If you are using the default `AccessDeniedHandler`, the browser will get an HTTP 403 and display a poor error message.
[[servlet-considerations-csrf-login]]
=== Logging Out
[NOTE]
====
One might ask why the expected `CsrfToken` isn't stored in a cookie by default.
This is because there are known exploits in which headers (i.e. specify the cookies) can be set by another domain.
This is the same reason Ruby on Rails https://weblog.rubyonrails.org/2011/2/8/csrf-protection-bypass-in-ruby-on-rails/[no longer skips CSRF checks when the header X-Requested-With is present].
See http://lists.webappsec.org/pipermail/websecurity_lists.webappsec.org/2011-February/007533.html[this webappsec.org thread] for details on how to perform the exploit.
Another disadvantage is that by removing the state (i.e. the timeout) you lose the ability to forcibly terminate the token if it is compromised.
====
A simple way to mitigate an active user experiencing a timeout is to have some JavaScript that lets the user know their session is about to expire.
The user can click a button to continue and refresh the session.
Alternatively, specifying a custom `AccessDeniedHandler` allows you to process the `InvalidCsrfTokenException` any way you like.
For an example of how to customize the `AccessDeniedHandler` refer to the provided links for both <<nsa-access-denied-handler,xml>> and https://github.com/spring-projects/spring-security/blob/3.2.0.RC1/config/src/test/groovy/org/springframework/security/config/annotation/web/configurers/NamespaceHttpAccessDeniedHandlerTests.groovy#L64[Java configuration].
Finally, the application can be configured to use <<csrf-cookie,CookieCsrfTokenRepository>> which will not expire.
As previously mentioned, this is not as secure as using a session, but in many cases can be good enough.
[[csrf-login]]
==== Logging In
In order to protect against https://en.wikipedia.org/wiki/Cross-site_request_forgery#Forging_login_requests[forging log in requests] the log in form should be protected against CSRF attacks too.
Since the `CsrfToken` is stored in HttpSession, this means an HttpSession will be created as soon as `CsrfToken` token attribute is accessed.
While this sounds bad in a RESTful / stateless architecture the reality is that state is necessary to implement practical security.
Without state, we have nothing we can do if a token is compromised.
Practically speaking, the CSRF token is quite small in size and should have a negligible impact on our architecture.
A common technique to protect the log in form is by using a JavaScript function to obtain a valid CSRF token before the form submission.
By doing this, there is no need to think about session timeouts (discussed in the previous section) because the session is created right before the form submission (assuming that <<csrf-cookie,CookieCsrfTokenRepository>> isn't configured instead), so the user can stay on the login page and submit the username/password when he wants.
In order to achieve this, you can take advantage of the `CsrfTokenArgumentResolver` provided by Spring Security and expose an endpoint like it's described on <<mvc-csrf-resolver,here>>.
[[csrf-logout]]
==== Logging Out
Adding CSRF will update the LogoutFilter to only use HTTP POST.
It is important to <<csrf-considerations-logout,require CSRF for log out>> requests to protect against forging log out attempts.
If CSRF protection is enabled (default), Spring Security's `LogoutFilter` to only process HTTP POST.
This ensures that log out requires a CSRF token and that a malicious user cannot forcibly log out your users.
One approach is to use a form for log out.
The easiest approach is to use a form to log out.
If you really want a link, you can use JavaScript to have the link perform a POST (i.e. maybe on a hidden form).
For browsers with JavaScript that is disabled, you can optionally have the link take the user to a log out confirmation page that will perform the POST.
If you really want to use HTTP GET with logout you can do so, but remember this is generally not recommended.
For example, the following Java Configuration will perform logout with the URL /logout is requested with any HTTP method:
For example, the following Java Configuration will perform logout with the URL `/logout` is requested with any HTTP method:
.Log out with HTTP GET
====
[source,java]
----
@EnableWebSecurity
@ -392,7 +301,7 @@ public class WebSecurityConfig extends
There are two options to using CSRF protection with multipart/form-data.
Each option has its tradeoffs.
* <<csrf-multipartfilter,Placing MultipartFilter before Spring Security>>
* <<csrf-include-csrf-token-in-action,Include CSRF token in action>>
[[servlet-considerations-csrf-timeouts]]
=== CSRF and Session Timeouts
By default Spring Security stores the CSRF token in the `HttpSession`.
This can lead to a situation where the session expires which means there is not an expected CSRF token to validate against.
We've already discussed <<csrf-considerations-login,general solutions>> to session timeouts.
This section discusses the specifics of CSRF timeouts as it pertains to the servlet support.
It is simple to change storage of the expected CSRF token to be in a cookie.
For details, refer to the <<servlet-csrf-configure-custom-repository>> section.
If a token does expire, you might want to customize how it is handled by specifying a custom `AccessDeniedHandler`.
The custom `AccessDeniedHandler` can process the `InvalidCsrfTokenException` any way you like.
For an example of how to customize the `AccessDeniedHandler` refer to the provided links for both <<nsa-access-denied-handler,xml>> and https://github.com/spring-projects/spring-security/blob/3.2.0.RC1/config/src/test/groovy/org/springframework/security/config/annotation/web/configurers/NamespaceHttpAccessDeniedHandlerTests.groovy#L64[Java configuration].
// FIXME: We should add a custom AccessDeniedHandler section in the reference and update the links above
[[servlet-csrf-considerations-multipart]]
=== Multipart (file upload)
We have <<csrf-considerations-multipart,already discussed>> how protecting multipart requests (file uploads) from CSRF attacks causes a https://en.wikipedia.org/wiki/Chicken_or_the_egg[chicken and the egg] problem.
This section discusses how to implement placing the CSRF token in the <<servlet-csrf-considerations-multipart-body,body>> and <<servlet-csrf-considerations-multipart-url,url>> within a servlet application.
[NOTE]
====
Before you integrate Spring Security's CSRF protection with multipart file upload, ensure that you can upload without the CSRF protection first.
More information about using multipart forms with Spring can be found within the https://docs.spring.io/spring/docs/3.2.x/spring-framework-reference/html/mvc.html#mvc-multipart[17.10 Spring's multipart (file upload) support] section of the Spring reference and the https://docs.spring.io/spring/docs/3.2.x/javadoc-api/org/springframework/web/multipart/support/MultipartFilter.html[MultipartFilter javadoc].
More information about using multipart forms with Spring can be found within the https://docs.spring.io/spring/docs/5.2.x/spring-framework-reference/web.html#mvc-multipart[1.1.11. Multipart Resolver] section of the Spring reference and the https://docs.spring.io/spring/docs/5.2.x/javadoc-api/org/springframework/web/multipart/support/MultipartFilter.html[MultipartFilter javadoc].
====
[[csrf-multipartfilter]]
===== Placing MultipartFilter before Spring Security
The first option is to ensure that the `MultipartFilter` is specified before the Spring Security filter.
[[servlet-csrf-considerations-multipart-body]]
==== Place CSRF Token in the Body
We have <<csrf-considerations-multipart-body,already discussed>> the tradeoffs of placing the CSRF token in the body.
In this section we will discuss how to configure Spring Security to read the CSRF from the body.
In order to read the CSRF token from the body, the `MultipartFilter` is specified before the Spring Security filter.
Specifying the `MultipartFilter` before the Spring Security filter means that there is no authorization for invoking the `MultipartFilter` which means anyone can place temporary files on your server.
However, only authorized users will be able to submit a File that is processed by your application.
In general, this is the recommended approach because the temporary file upload should have a negligble impact on most servers.
In general, this is the recommended approach because the temporary file upload should have a negligible impact on most servers.
// FIXME: Document Spring Boot
To ensure `MultipartFilter` is specified before the Spring Security filter with java configuration, users can override beforeSpringSecurityFilterChain as shown below:
.Initializer MultipartFilter
====
[source,java]
----
public class SecurityApplicationInitializer extends AbstractSecurityWebApplicationInitializer {
@ -435,9 +368,12 @@ public class SecurityApplicationInitializer extends AbstractSecurityWebApplicati
}
}
----
====
To ensure `MultipartFilter` is specified before the Spring Security filter with XML configuration, users can ensure the <filter-mapping> element of the `MultipartFilter` is placed before the springSecurityFilterChain within the web.xml as shown below:
.web.xml - MultipartFilter
====
[source,xml]
----
<filter>
@ -457,34 +393,28 @@ To ensure `MultipartFilter` is specified before the Spring Security filter with
<url-pattern>/*</url-pattern>
</filter-mapping>
----
====
[[csrf-include-csrf-token-in-action]]
===== Include CSRF token in action
If allowing unauthorized users to upload temporariy files is not acceptable, an alternative is to place the `MultipartFilter` after the Spring Security filter and include the CSRF as a query parameter in the action attribute of the form.
[[servlet-csrf-considerations-multipart-url]]
==== Include CSRF Token in URL
If allowing unauthorized users to upload temporary files is not acceptable, an alternative is to place the `MultipartFilter` after the Spring Security filter and include the CSRF as a query parameter in the action attribute of the form.
Since the `CsrfToken` is exposed as an `HttpServletRequest` <<servlet-csrf-include,request attribute>>, we can use that to create an `action` with the CSRF token in it.
The disadvantage to this approach is that query parameters can be leaked.
More genearlly, it is considered best practice to place sensitive data within the body or headers to ensure it is not leaked.
Additional information can be found in https://www.w3.org/Protocols/rfc2616/rfc2616-sec15.html#sec15.1.3[RFC 2616 Section 15.1.3 Encoding Sensitive Information in URI's].
[[servlet-csrf-considerations-override-method]]
=== HiddenHttpMethodFilter
We have <<csrf-considerations-multipart-body,already discussed>> the trade-offs of placing the CSRF token in the body.
==== HiddenHttpMethodFilter
The HiddenHttpMethodFilter should be placed before the Spring Security filter.
In general this is true, but it could have additional implications when protecting against CSRF attacks.
Note that the HiddenHttpMethodFilter only overrides the HTTP method on a POST, so this is actually unlikely to cause any real problems.
However, it is still best practice to ensure it is placed before Spring Security's filters.
=== Overriding Defaults
Spring Security's goal is to provide defaults that protect your users from exploits.
This does not mean that you are forced to accept all of its defaults.
For example, you can provide a custom CsrfTokenRepository to override the way in which the `CsrfToken` is stored.
You can also specify a custom RequestMatcher to determine which requests are protected by CSRF (i.e. perhaps you don't care if log out is exploited).
In short, if Spring Security's CSRF protection doesn't behave exactly as you want it, you are able to customize the behavior.
Refer to the <<nsa-csrf>> documentation for details on how to make these customizations with XML and the `CsrfConfigurer` javadoc for details on how to make these customizations when using Java configuration.
In Spring's Servlet support, overriding the HTTP method is done using https://docs.spring.io/spring-framework/docs/5.2.x/javadoc-api/org/springframework/web/filter/reactive/HiddenHttpMethodFilter.html[HiddenHttpMethodFilter].
More information can be found in https://docs.spring.io/spring/docs/5.2.x/spring-framework-reference/web.html#mvc-rest-method-conversion[HTTP Method Conversion] section of the reference documentation.
@ -112,7 +112,7 @@ The `Acl` will be invoked with the required permissions to check if all of them
This tag also supports the `var` attribute, in the same way as the `authorize` tag.
[[taglibs-csrfinput]]
=== The csrfInput Tag
If CSRF protection is enabled, this tag inserts a hidden form field with the correct name and value for the CSRF protection token.
If CSRF protection is not enabled, this tag outputs nothing.
@ -133,7 +133,7 @@ Spring Security handles Spring forms automatically.
</form>
----
[[taglibs-csrfmeta]]
=== The csrfMetaTags Tag
If CSRF protection is enabled, this tag inserts meta tags containing the CSRF protection token form field and header names and CSRF protection token value.
These meta tags are useful for employing CSRF protection within JavaScript in your applications.