CSRF tokens are not about encrypting data; they’re a clever way to ensure a request originated from your legitimate application, not a malicious one.

Let’s see this in action. Imagine a simple web form that transfers money.

<form action="/transfer" method="POST">
  <input type="text" name="recipient" placeholder="Recipient Account">
  <input type="number" name="amount" placeholder="Amount">
  <input type="hidden" name="csrf_token" value="a1b2c3d4e5f6..."> <!-- This is the magic -->
  <button type="submit">Transfer</button>
</form>

When the user submits this form, the browser sends the recipient, amount, and crucially, the csrf_token to the /transfer endpoint on the server.

The server then performs a check. It looks at the csrf_token sent with the request and compares it against a csrf_token it previously generated and stored, usually in the user’s session. If they match, the request is considered legitimate, and the transfer proceeds. If they don’t match, the server rejects the request, preventing any unauthorized action.

The problem CSRF tokens solve is Cross-Site Request Forgery. Imagine you’re logged into your bank’s website. You then visit a malicious site that has a hidden form. This malicious site’s form could look like this:

<form action="https://your-bank.com/transfer" method="POST">
  <input type="hidden" name="recipient" value="attacker-account">
  <input type="hidden" name="amount" value="1000">
  <!-- No csrf_token here, or a fake one -->
  <button type="submit">Click Me!</button>
</form>

If you’re still logged into your bank, and you somehow trigger this hidden form (e.g., by visiting the malicious page, or clicking a seemingly innocuous link), your browser will automatically send your bank cookies along with the request. The bank’s server sees a valid session cookie and, without a CSRF token check, would happily process the transfer to the attacker’s account. The CSRF token breaks this attack chain because the malicious site cannot obtain the correct CSRF token for your bank session.

Internally, the process involves a server-side framework (like Django, Ruby on Rails, or Express with a CSRF middleware) generating a unique, unpredictable token for each user session. This token is then embedded in forms as a hidden field. When the form is submitted, the server validates that the token in the request matches the one associated with the user’s session. The "cryptography" isn’t about strong encryption of the token itself, but rather the unpredictability and uniqueness of the token generation, making it impossible for an attacker to guess or forge.

The most surprising thing is how many systems get this wrong by only checking the token on POST requests. A truly robust CSRF protection checks the token on any state-changing HTTP method (POST, PUT, DELETE, PATCH) and often requires a custom header for AJAX requests to prevent them from being tricked by simple form submissions.

The next step in securing web applications is understanding how these tokens are managed across different request types, especially with modern JavaScript-heavy frontends.

Want structured learning?

Take the full Cryptography course →