Search code examples
csrfcsrf-token

How do anti-CSRF tokens work in SPA-API communications?


Recently I'm studying some basics of Web security and there is something I couldn't understand. How do anti-CSRF tokens work in SPA-API communications?

As far as I understand, anti-CSRF is used in SPA-API communications as followings;

  1. The browser sends a login request to the API.
  2. The API servers generates a token and sends it back to the browser.
  3. The browser stores it, and when the browser makes the next request, token with be sent together.
  4. The API can make sure that the request came from the genuine front-end because it contains the token.

A question pops up in my mind--how can it prevent CSRF? If the token is stored in cookie, it will automatically be sent to API whenever a request happens, like usual session cookies. And even if it's stored in other storage(like session storage or local storage), it can be accessed using JavaScript.

So once users are attracted to the attacker's site, anti-CSRF tokens are completely useless.

On the top of that, I can't understand what's the difference between anti-CSRF token and usual cookies used in authentication/authorization……

Maybe I've made a terrible misunderstanding about how anti-CSRF tokes work. Please put a finger on what's wrong about it.


Solution

  • One of the most common CSRF vulnerabilities exists when an attacker can submit a request to an endpoint using an authenticated user's cookies. If you're not using cookies (i.e., to authenticate a user's request) or some other automatic authentication technique (like HTTP Basic Authentication), then there's generally no need for CSRF tokens.

    Example #1:

    Let's say you're using a REST API that depends on an access token or bearer token for authentication. This token is usually submitted in the HTTP Authorization header (not a cookie). In this case, as long as authentication isn't automatic (e.g., using a cookie), then there's no need for a CSRF token.

    Example #2:

    In this case, let's say the browser does send a session cookie to a web service/API to authenticate the request. Then, yes, you would be vulnerable to CSRF if anti-CSRF controls aren't implemented. One way to prevent this is to provide an anti-CSRF token to the browser when the SPA is loaded. The browser can then send that token with the request to the endpoint. The web service will then have to validate that token when the request is received.

    There are a number of ways that this validation can occur. This could be done using double-submit cookies, a cookie-to-header token, cryptographic techniques, or even a shared database.

    Using Anti-CSRF Tokens:

    Anti-CSRF tokens generally should not be stored in cookies. As stated in the OWASP CSRF Prevention Cheat Sheet:

    A CSRF token can be included in the <meta> tag. All subsequent calls in the page can extract the CSRF token from this <meta> tag. It can also be stored in a JavaScript variable or anywhere on the DOM. However, it is not recommended to store it in cookies or browser local storage.

    For example, an anti-CSRF token might get embedded in the page as:

    <meta name="csrf-token" content="{{ csrf_token() }}">
    

    Where the csrf_token() calls some server-side function that embeds the token in the tag.

    It can then be read in JavaScript using:

    let csrf_token = document.querySelector("meta[name='csrf-token']").getAttribute("content");
    

    And then transmitted to the server when an API request is made (e.g., in a X-CSRF-Token header in a POST request). In addition, the token should be unique to the session.

    However, even if a token were to be stored in a cookie, the cookie could be set with the HttpOnly header. This prevents the cookie from being read by JavaScript. This is more so useful in mitigating cross-site scripting (XSS) attacks.

    Additional Info:

    Other good resources about CSRF in general: