Understanding Cross-Site Request Forgery (CSRF)

Cross-Site Request Forgery (CSRF) is a type of web security vulnerability where an attacker tricks a user into performing unwanted actions on a web application where they are authenticated. CSRF exploits the trust that a web application has in the user’s browser and can lead to serious security breaches, such as unauthorized transactions, data modification, and account takeovers.

What is CSRF?

  • The malicious site does not have direct access to the victim’s cookies—browsers enforce same-origin policy, which prevents scripts from Site A from reading cookies of Site B.
  • However, CSRF bypasses this restriction because the attack doesn’t need to access the cookies directly. Instead, the browser automatically includes cookies (such as session tokens) when requesting a trusted site (e.g., bank.com).

So, when the victim visits the malicious page:

  • The attacker’s script or hidden form submits a request to bank.com.
  • The browser includes session cookies belonging to bank.com in the request.
  • bank.com sees a legitimate request from an authenticated user and processes it.

This is why CSRF is dangerous despite the Same-Origin Policy—it exploits the implicit trust that web applications place in browsers. Defence mechanisms like CSRF tokens, SameSite cookies, and custom headers are crucial to prevent this.

How CSRF Works

A CSRF attack typically involves three main components:

  • Authenticated User: The victim is logged into a web application.
  • Malicious Request: The attacker crafts a request that appears legitimate and forces the victim’s browser to send it.
  • Exploited Trust: Since the request comes from the victim’s browser, the application processes it with the victim’s authenticated session.

Example of a CSRF Attack

Consider a banking website where a user can transfer money using a simple request like:

POST /transfer HTTP/1.1  
Host: bank.com  
Cookie: sessionid=xyz123  

amount=1000&to_account=987654
Python

If the user is logged in and their session is active, the request will be successfully processed.

An attacker can create a malicious link or script that automatically submits this request when the user visits a malicious page. For example:

<img src="http://bank.com/transfer?amount=1000&to_account=987654" />
Python

If the victim visits a compromised website while being logged into their bank, their browser will automatically send the request, transferring money without their consent.

Why CSRF is Dangerous

CSRF attacks can have severe consequences, including:

  • Financial Fraud: Unauthorized bank transactions.
  • Account Takeover: Changing user passwords or email addresses.
  • Data Manipulation: Deleting or modifying user data.
  • Privilege Escalation: Granting admin rights to an attacker.

Since CSRF exploits authenticated sessions, it is particularly dangerous for applications with sensitive operations.

Preventing CSRF Attacks

To mitigate CSRF vulnerabilities, developers should implement multiple layers of defence.

CSRF Tokens (Anti-CSRF Tokens)

A CSRF token is a unique, unpredictable value generated by the server and included in every state-changing request. The server verifies this token before processing the request.

Example:

The server sends a form with a hidden CSRF token:

<form action="/transfer" method="POST">
  <input type="hidden" name="csrf_token" value="abcd1234">
  <input type="text" name="amount">
  <input type="text" name="to_account">
  <input type="submit" value="Transfer">
</form>
Python

On submission, the server checks if the token matches the expected value before processing the request.

Setting the SameSite attribute in cookies helps prevent browsers from sending cookies with cross-site requests.

Set-Cookie: sessionid=xyz123; Secure; HttpOnly; SameSite=Strict
Python

  • SameSite=Strict: Prevents cookies from being sent with any cross-origin request.
  • SameSite=Lax: Allows cookies for top-level GET requests but blocks them for other requests.

Using Custom Headers

Requiring requests to contain a custom header (e.g., X-Requested-With) ensures they originate from the intended client.

Example using AJAX:

fetch('/transfer', {
  method: 'POST',
  headers: {
    'X-Requested-With': 'XMLHttpRequest'
  },
  body: JSON.stringify({ amount: 1000, to_account: '987654' })
});
Python

The server rejects requests without the X-Requested-With header.

User Authentication Measures

    • Re-authentication: Ask users to re-enter their password for sensitive actions.
    • Multi-Factor Authentication (MFA): Adds an extra layer of security.

    Content Security Policy (CSP)

    A CSP can help prevent CSRF by restricting allowed sources of executable scripts:

    Content-Security-Policy: default-src 'self'; script-src 'self'
    Python

    Does a CORS setup prevent a CSRF attack?

    No, CORS (Cross-Origin Resource Sharing) does not prevent CSRF attacks.

    Why?

    • CORS controls which origins can make AJAX (XHR/Fetch) requests and read responses.
    • CSRF does not rely on reading responses—it only exploits the fact that the browser will automatically send cookies with cross-origin requests.

    How CORS and CSRF Differ

    FeatureCORS ProtectionCSRF Protection
    Controls which origins can make requestsYesNo
    Prevents sending cookies with cross-origin requestsNo (Cookies are sent unless SameSite=Strict)Yes (If SameSite=Strict)
    Prevents unauthorized state-changing requestsNoYes (If CSRF tokens are used)
    Prevents reading responses from unauthorized originsYesNo (CSRF doesn’t need response data)

    Example: Why CORS Doesn’t Stop CSRF

    Imagine a banking site (bank.com) with CORS set to allow only requests from trusted.com.

    CSRF Attack Scenario

    • Victim logs into bank.com and has an active session.
    • Victim visits evil.com, which has a hidden form:
    <form action="https://bank.com/transfer" method="POST">
        <input type="hidden" name="amount" value="1000">
        <input type="hidden" name="to_account" value="987654">
        <input type="submit">
    </form>
    <script> document.forms[0].submit(); </script>
    Python

    • When the form is submitted, the browser includes the victim’s session cookies for bank.com, making the request look legitimate.
    • bank.com processes the transfer even though the request came from evil.com.

    CORS does not block this because:

    • The browser is allowed to send cookies to bank.com.
    • bank.com does not need to send a response back to evil.com—CSRF succeeds without reading data.

    When Does CORS Help?

    CORS prevents cross-origin JavaScript from reading sensitive responses. If an attacker tries:

    fetch("https://bank.com/transactions", { credentials: "include" })
      .then(response => response.json())
      .then(data => console.log(data)); // Blocked by CORS!
    Python

    The browser blocks the response unless bank.com explicitly allows it.

    Conclusion

      CSRF is a critical web security vulnerability that exploits trust between users and applications. Implementing CSRF tokens, SameSite cookies, custom headers, and authentication measures can effectively mitigate these attacks. Web developers must be proactive in securing their applications to protect users from unauthorized actions.

      Leave a Comment