Skip to main content
← πŸ“„ HTML & the platformΒ·Module A3 Β· Lesson 15
TaskBuild a transfer form that's CSRF-safe. <form method='post' action='/transfer'> with a hidden input name='_csrf' value='SERVER_RENDERED_TOKEN', a labeled input for 'to' (text) and 'amount' (number, min 1, required), and a submit button.

CSRF tokens: why your form needs a secret the attacker can't read

100 XP9 min
Theory

The attack you're defending against

You're logged into bank.com. An attacker tricks you into visiting evil.com. evil.com ships HTML like:

<form action="https://bank.com/transfer" method="post">
  <input name="to" value="attacker" />
  <input name="amount" value="9999" />
</form>
<script>document.forms[0].submit()</script>

Your browser cheerfully attaches your bank.com cookies (you're logged in!) and POSTs the transfer. That's CSRF β€” Cross-Site Request Forgery.

The fix: server-rendered secret in the form

The server puts a random token into your form when it renders. The token is tied to your session, stored server-side, and is NOT readable from other origins (different origin = can't read the HTML the server sent you).

<form action="/transfer" method="post">
  <input type="hidden" name="_csrf" value="a7f3...c4b2" />
  <input name="to" />
  <input name="amount" />
</form>

The server checks: "does _csrf match what I gave this session?" If not β†’ 403. The attacker on evil.com can't read your CSRF cookie via JavaScript (different origin), can't read the rendered HTML (different origin), and can't guess the random token. Forgery blocked.

Three places people get this wrong

  1. One global token reused per session β€” works but leaks one token across many forms; safer is per-form rotation.
  2. Token in URL β€” leaks via Referer header, browser history, server logs. Always put it in a hidden form field, never a query string.
  3. No token on POST that "feels safe" β€” newsletter sign-up, "follow user" buttons. ANY state-changing POST needs a token.
πŸ”’

Sign up to start coding

Theory is open to everyone. The interactive editor, live preview, and check are unlocked with a 7-day free trial β€” card required, cancel anytime.

Sign up β€” free trial β†’

First 10 lessons in each track are free. No card needed for those.

← PreviousNext lesson β†’

Get one Python or web tip a day β€” by email

Short, hand-written, no spam. Unsubscribe in one click.