diff --git a/docs/manual/src/docbook/csrf.xml b/docs/manual/src/docbook/csrf.xml new file mode 100644 index 0000000000..f229bb0373 --- /dev/null +++ b/docs/manual/src/docbook/csrf.xml @@ -0,0 +1,203 @@ + + + Cross Site Request Forgery (CSRF) + + This section discusses Spring Security's + Cross Site Request Forgery (CSRF) support. +
+ CSRF Attacks + Before we discuss how Spring Security can protect applications from CSRF attacks, we will explain what a CSRF + attack is. Let's take a look at a concrete example to get a better understanding. + 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 HTTP request might look like: + + 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: + + + + + 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. +
+
+ Using Spring Security CSRF Support + 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: + + + Use proper HTTP verbs + + + Configure CSRF Protection + + + Include the CSRF Token + + +
+ 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 not a limitation of Spring Security's support, but instead a general requirement for proper CSRF prevention. +
+
+ Configure CSRF Protection + The next step is to include Spring Security's CSRF protection within your application. If you are using the XML configuration, this can be done + using the <csrf /> element: + + ... + + +]]> + CSRF protection is enabled by default with Java configuration. If you would like to disable CSRF, the corresponding Java configuration can be + seen below: + +
+
+ Include the CSRF Token +
+ Form Submissions + The last step is to ensure that you include the CSRF token in all PATCH, POST, PUT, and DELETE methods. This can be done using + the _csrf request attribute to obtain the current CsrfToken. An example of doing this with a JSP is shown below: + +
+ + +
]]>
+ + If you are using Spring MVC <form:form> tag, the CsrfToken is automatically included for you using the CsrfRequestDataValueProcessor. + +
+
+ Ajax Requests + If you 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: + + + + + + ... + + ...]]> + You can then include the token within all your AJAX requests. If you were using JQuery, this could be done with the following: + +
+
+
+
+ CSRF Caveats + There are a few caveats when implementing CSRF. +
+ 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. + + One might ask why the CsrfToken isn't stored in a cookie. This is because there are known exploits in which headers + (i.e. specify the cookies) can be set by another domain. Another disadvantage is that by removing the state (i.e. the timeout) you lose the ability + to forcibly terminate the token if something got 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 + anyway you like. For an example of how to customize the AccessDeniedHandler refer to the provided links for both xml and Java + configuration. +
+
+ Logging In + In order to protect against 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. +
+
+ Logging Out + Adding CSRF will update the LogoutFilter to only use 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. 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. +
+
+ 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 <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. +
+
diff --git a/docs/manual/src/docbook/index.xml b/docs/manual/src/docbook/index.xml index dd0af05bbe..422427d29b 100644 --- a/docs/manual/src/docbook/index.xml +++ b/docs/manual/src/docbook/index.xml @@ -130,6 +130,7 @@ +