For any application authentication topic is recurrent. How will I manage authentication and subsequent calls are secured to my application. Growing footprint of stateless applications made the use of JWT token very popular, they are easy to generate and to verify.

Below I summarised my readings about CSRF to see how a standard application can be secured against CSRF.

What is CSRF

CSRF (or XSRF) stands for cross site request forgery, it is a way for one to impersonate an authenticated user and send (evil) requests on his behalf. For a more lengthy but very insightful description refer to OSWASP site on the topic.

As on image is often worth more than any explanation here it is


How to prevent CSRF

2 criteria are important to understand how to prevent CSRF attacks.

  • There are 2 main types of request websites are emitting: standard requests (e.g.: form submission), and Ajax / XHR requests
  • It depends the architecture of your application whether it is stateless or stateful

Standard designs involve a CSRF token


If the website can be stateful (even only for this security handling via db or a redis) the synchronizer token pattern is often used; otherwise the double summit cookie pattern is used.

Standard requests are usually protected sending along a custom HTTP header which can be retrieved from an hidden field in the form.

<form action="/transfer.do" method="post">
<input type="hidden" name="CSRFToken" value="OWY4NmQwODE4ODRjN2Q2NTlhMmZ...==">
[...]
</form>

For Ajax requests which do not have access to form input fields they are passing an extra parameters. This extra parameter value comes from the server, it can be returned in a cookie that only a client from the same origin can read and so send back in a HTTP header the value. The server can then check the value in the cookie and in the header are matching.

<script type="text/javascript">
    var csrf_token = document.querySelector("meta[name='csrf-token']").getAttribute("content");

    axios.defaults.headers.post['anti-csrf-token'] = csrf_token;
    axios.defaults.headers.put['anti-csrf-token'] = csrf_token;
    axios.defaults.headers.delete['anti-csrf-token'] = csrf_token;
    axios.defaults.headers.patch['anti-csrf-token'] = csrf_token;

    // Axios does not create an object for TRACE method by default, and has to be created manually.
    axios.defaults.headers.trace = {}
    axios.defaults.headers.trace['anti-csrf-token'] = csrf_token
</script>

It prevents an attacker to send the same token as it cannot read the cookie content - as his website is from a different origin. The cookied used to send back the token is a first party cookie, so a SameSite cookie makes sense here (SameSite=Strict).

Spring security discusses this topic further and Angular brings more about Ajax calls.