We're sorry but this app doesn't work properly without JavaScript enabled. Please enable it to continue.

This lesson's interactive features are locked, please to keep using them

CSRF Tokens

A CSRF token proves that a state-changing request includes a secret value issued by the application, not just a cookie the browser attached automatically.

The synchronizer token pattern stores a random token in the user's server-side session. The server generates it when the session is created:

import { randomBytes } from "node:crypto";

const csrfToken = randomBytes(32).toString("base64url");

Then each protected form has the session's token set in a hidden field:

<input type="hidden" name="csrfToken" value="SESSION_CSRF_TOKEN" />

When the form is submitted, the server compares the submitted csrfToken with the token stored in the authenticated session, and any missing tokens, non-string values, or mismatches are forbidden. Also, be sure to use Node's timingSafeEqual to compare Buffer values instead of raw strings, which can prevent timing attacks that could reveal the token's value.

So... What Does CSRF Protect Against?

Remember, an attacker's page can trick the browser into sending an authenticated session cookie to your server on a request the user didn't intend to send. But the browser can't automatically include a valid CSRF token, because the token isn't an automatically included cookie.

XSS can get around CSRF tokens by executing JavaScript that reads a token from the DOM and submits a valid request... you need to prevent both vulnerabilities.

Assignment

Bearly Secure's forms already carry CSRF tokens, and most POST handlers already call csrfTokensMatch before doing anything. There are two problems: csrfTokensMatch is a stub that returns true for any token, and the checkout handler never calls it at all.

Implement the token comparison, then protect checkout.

With Bearly Secure still running, run and submit the CLI tests from the project root.