<chapter xmlns="http://docbook.org/ns/docbook" version="5.0" xml:id="csrf"
    xmlns:xlink="http://www.w3.org/1999/xlink">
    <info>
        <title>Cross Site Request Forgery (CSRF)</title>
    </info>
    <para>This section discusses Spring Security's <link xlink:href="http://en.wikipedia.org/wiki/Cross-site_request_forgery">
        Cross Site Request Forgery (CSRF)</link> support.</para>
    <section>
        <title>CSRF Attacks</title>
        <para>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.</para>
        <para>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:</para>
            <programlisting><![CDATA[POST /transfer HTTP/1.1
Host: bank.example.com
Cookie: JSESSIONID=randomid; Domain=bank.example.com; Secure; HttpOnly
Content-Type: application/x-www-form-urlencoded

amount=100.00&routingNumber=1234&account=9876
]]></programlisting>
        <para>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:</para>
            <programlisting language="xml"><![CDATA[<form action="https://bank.example.com/transfer" method="post">
  <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>]]></programlisting>
        <para>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.</para>
        <para>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?</para>
    </section>
    <section>
        <title>Synchronizer Token Pattern</title>
        <para>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.</para>
        <para>One solution is to use the
            <link xlink:href="https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)_Prevention_Cheat_Sheet#General_Recommendation:_Synchronizer_Token_Pattern">Synchronizer
            Token Pattern</link>. 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.</para>
        <para>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.</para>
        <para>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:</para>
             <programlisting><![CDATA[POST /transfer HTTP/1.1
Host: bank.example.com
Cookie: JSESSIONID=randomid; Domain=bank.example.com; Secure; HttpOnly
Content-Type: application/x-www-form-urlencoded

amount=100.00&routingNumber=1234&account=9876&_csrf=<secure-random>
]]></programlisting>
        <para>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.</para>
    </section>
    <section>
        <title>Using Spring Security CSRF Support</title>
        <para>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:</para>
            <orderedlist inheritnum="ignore" continuation="restarts">
              <listitem>
                <para><link linkend="csrf-use-proper-verbs">Use proper HTTP verbs</link></para>
              </listitem>
              <listitem>
                <para><link linkend="csrf-configure">Configure CSRF Protection</link></para>
              </listitem>
              <listitem>
                <para><link linkend="csrf-include-csrf-token">Include the CSRF Token</link></para>
              </listitem>
            </orderedlist>
            <section xml:id="csrf-use-proper-verbs">
                <title>Use proper HTTP verbs</title>
                <para>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.</para>
            </section>
            <section xml:id="csrf-configure">
                <title>Configure CSRF Protection</title>
                <para>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 <link linkend="nsa-csrf">&lt;csrf /&gt;</link> element:</para>
                <programlisting language="xml"><![CDATA[<http ...>
    ...
    <csrf />
</http>
]]></programlisting>
                <para>CSRF protection is enabled by default with Java configuration. If you would like to disable CSRF, the corresponding Java configuration can be
                    seen below:</para>
                <programlisting language="java"><![CDATA[@EnableWebSecurity
@Configuration
public class WebSecurityConfig extends
   WebSecurityConfigurerAdapter {

  @Override
  protected void configure(HttpSecurity http) throws Exception {
    http
      .csrf().disable()
      ...;
  }
}]]></programlisting>
            </section>
            <section xml:id="csrf-include-csrf-token">
                <title>Include the CSRF Token</title>
                <section xml:id="csrf-include-csrf-token-form">
                    <title>Form Submissions</title>
                    <para>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:</para>
                        <programlisting language="xml"><![CDATA[<c:url var="logoutUrl" value="/logout"/>
<form action="${logoutUrl}"
    method="post">
  <input type="submit"
    value="Log out" />
  <input type="hidden"
    name="${_csrf.parameterName}"
    value="${_csrf.token}"/>
</form>]]></programlisting>
                    <note>
                        <para>If you are using Spring MVC &lt;form:form&gt; tag, the <interfacename>CsrfToken</interfacename> is automatically included for you using the CsrfRequestDataValueProcessor.</para>
                    </note>
                </section>
                <section xml:id="csrf-include-csrf-token-ajax">
                    <title>Ajax Requests</title>
                    <para>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:</para>
                        <programlisting language="xml"><![CDATA[<html>
  <head>
    <meta name="_csrf" content="${_csrf.token}"/>
    <!-- default header name is X-CSRF-TOKEN -->
    <meta name="_csrf_header" content="${_csrf.headerName}"/>
    ...
  </head>
  ...]]></programlisting>
                    <para>You can then include the token within all your AJAX requests. If you were using JQuery, this could be done with the following:</para>
                    <programlisting language="javascript"><![CDATA[$(document).ajaxSend(function(e, xhr, options) {
  var token = $("meta[name='_csrf']").attr("content");
  var header = $("meta[name='_csrf_header']").attr("content");
  xhr.setRequestHeader(header, token);
});]]></programlisting>
                </section>
            </section>
    </section>
    <section>
        <title>CSRF Caveats</title>
        <para>There are a few caveats when implementing CSRF.</para>
        <section>
            <title>Timeouts</title>
            <para>One issue is that the expected CSRF token is stored in the HttpSession, so as soon as the HttpSession expires your configured
                <interfacename>AccessDeniedHandler</interfacename> will receive a InvalidCsrfTokenException. If you are using the default
                <interfacename>AccessDeniedHandler</interfacename>, the browser will get an HTTP 403 and display a poor error message.</para>
            <note>
                <para>One might ask why the <interfacename>CsrfToken</interfacename> 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.</para>
            </note>
            <para>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.</para>
            <para>Alternatively, specifying a custom <interfacename>AccessDeniedHandler</interfacename> allows you to process the <classname>InvalidCsrfTokenException</classname>
                anyway you like. For an example of how to customize the <interfacename>AccessDeniedHandler</interfacename> refer to the provided links for both xml and Java
                configuration.</para>
        </section>
        <section>
            <title>Logging In</title>
            <para>In order to protect against forging log in requests the log in form should be protected against CSRF attacks too. Since the <interfacename>CsrfToken</interfacename> is stored in
                HttpSession, this means an HttpSession will be created as soon as <interfacename>CsrfToken</interfacename> 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.</para>
        </section>
        <section>
            <title>Logging Out</title>
            <para>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.</para>
            <para>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.</para>
        </section>
        <section>
            <title>HiddenHttpMethodFilter</title>
            <para>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.</para>
            <para>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.</para>
        </section>
       </section>
    <section>
        <title>Overriding Defaults</title>
        <para>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.</para>
        <para>For example, you can provide a custom CsrfTokenRepository to override the way in which the <interfacename>CsrfToken</interfacename> is stored.</para>
        <para>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 <link linkend="nsa-csrf">&lt;csrf /&gt;</link>
            documentation for details on how to make these customizations with XML and the <classname>CsrfConfigurer</classname> javadoc for details on how to make these
            customizations when using Java configuration.</para>
    </section>
</chapter>
