Skip to content
Optimal Lab

Security · interactive

Cross-site request forgery (CSRF)

Browsers attach your cookies to every request sent to a site, no matter which page sent it. So another site can make your browser act on your behalf, using your logged-in session.

  1. bank.example

    You log in to bank.example. It sets a session cookie.

<!-- on evil.example -->
<form action="https://bank.example/transfer" method="POST">
  <input type="hidden" name="to" value="attacker">
  <input type="hidden" name="amount" value="500">
</form>
<script>document.forms[0].submit()</script>

You log in to bank.example. It sets a session cookie.

Bank's defense

The bank trusts any request that carries the session cookie.

step 1 of 5

Step 1 of 4

  1. 1

    You're logged in somewhere

    The bank set a session cookie. Your browser will send it with every request to bank.example.

    Normal and expected.

  2. 2

    Another site sends a request for you

    A hidden form or image tag on evil.example targets the bank. The attacker can't read the response, but doesn't need to.

    Only state-changing requests matter: transfers, password changes.

  3. 3

    Make cross-site requests different

    SameSite cookies stay home on cross-site POSTs. CSRF tokens prove the form came from your own page. The Origin header says who sent it.

    Use SameSite=Lax as the baseline, plus tokens or Origin checks.

  4. 4

    Never change state on GET

    SameSite=Lax still sends cookies on top-level GET navigations, so a GET that transfers money is still forgeable.

    • No defensestolen
    • SameSite=Lax cookieblocked
    • CSRF tokenblocked
    • Check the Origin headerblocked

In production

Tools and technologies

Frameworks and browsers now ship most CSRF defenses by default.

Not tied to one language — use these names when you search docs or design a system.