What is a Cross Site Request Forgery (CSRF) attack?

CSRF protection using csrf token

Cross site request forgery is a cyber attack where an attacker takes advantage of a logged in user’s session cookie and makes inappropriate request to the website that the user is authenticated to.

Consider an example, where a user logs in to his/her account in a bank’s website WeBank.com. In case of HTTP(Hyper Text Transfer Protocol), the user’s browser makes a request to the WeBank.com server, and the server authenticates the user by sending session ID as cookie back to the browser. This session ID(session cookie) persists as long as the user is logged in to the website.

HTTP/1.1 200 OK
Content-Type: text/html; charset=UTF-8
Set-Cookie: sessionId=1234; 
Cache-Control: no-cache
Content-Length: 1256

Consider a malicious attacker sends a fake URL FakeLink.com either through mail or message to the user. This URL FakeLink.com has an html code that contains a form which on submission makes a bank transfer of amount 1000 to the hacker’s bank account. The script includes code that automatically submits the form.

<form action="https://WeBank.com/transfer" method="POST">
    <input type="text" name="to" value="hacker">
    <input type="text" name="amount" value="1000">
</form>
<script>document.forms[0].submit();</script>

When the user clicks on this link on other tab, with the user still logged in to the bank account, the request will be made from the user’s browser to bank server WeBank.com, which includes the same session cookie as provided by the bank server.

POST /transfer
Host: WeBank.com
Cookie: sessionId=1234
to=hacker&amount=1000

Since the WeBank.com server gets request from the authenticated user with valid session ID from the cookie, It will accept the request considering it to be made by the user and transfers the money to the hacker’s account.

This is how a cross site request forgery happens, in order to prevent this attack, a CSRF token is included in the forms. A CSRF token is a random token that is generated by the web server whenever a user makes request to it.

<form id="form" method="POST">
<input type="hidden" name="csrfmiddlewaretoken" value="m3SplaK7Cb7oxESLwj3cE1BuDyM4WE96NuUeh">
<input type="text" name="amount" placeholder="Enter amount">
<button type="submit">Transfer</button>
</form>

In Django, developers pass the “csrf_token” in the form. Whenever the form is submitted, a unique csrf token is generated by the server for the session. It must be included in every form submission or request to the server.

<form method="POST" action="/transfer/">
    {% csrf_token %}
    <input type="text" name="to" value="recipient">
    <input type="text" name="amount" placeholder="Enter amount">
    <button type="submit">Transfer</button>
</form>

To protect your views, Django automatically enforces CSRF protection for all POST, PUT, PATCH, and DELETE requests.

If you don’t include the {% csrf_token %} tag:

  1. Django rejects the request, showing a 403 Forbidden error.

  2. This is because Django couldn’t verify that the request is coming from a trusted source.

When the user submits the form, the browser sends the form data along with the CSRF token to the server. Django checks if the token matches the one stored in the user’s session. If it matches, the request is allowed. If it doesn’t match, then Django rejects the request with a 403 Forbidden error.

The CSRF token is sent as part of the request payload, just like other form fields (e.g., username, password, etc.), and it is completely separate from the cookie data.

POST /transfer
Host: WeBank.com
Cookie: sessionid=1234

csrf_token=abc123xyz&to=recipient&amount=1000

How “csrf_token” prevents CSRF attack?

  • The URL sent by hacker FakeLink.com doesn’t contain “csrf_token” as it is unique to the session. Hackers cannot access this token because it is not stored in cookies(which are automatically sent with requests).

  • csrf_token is embedded in the HTML code, the browser’s same-origin policy doesn’t allow FakeLink.com or other website to inspect or interact with the DOM of WeBank.com. So there is no way the hacker can get the token. The same-origin policy in web browsers ensures that scripts or requests originating from one domain cannot access the resources (HTML,CSS etc files) or data of another domain.

  • Also, unlike cookies, CSRF tokens are not automatically included in the request payload.

    Hence the requests from unknown websites are rejected by websites, that includes CSRF protection.

Even while sending data via JavaScript (using AJAX), we need to include CSRF token in the request to secure APIs.

CSRF token added to AJAX header

fetch('/transfer/', {
    method: 'POST',
    headers: {
        'X-CSRFToken': 'abc123xyz',
        'Content-Type': 'application/json',
    },
    body: JSON.stringify({ amount: 1000 }),
});

That is why it is advised not to click on unknown or suspicious links. Thankfully, CSRF tokens protects us from getting scammed from hackers.

Thank you for reading!!