HTML Tutorial 0/139 lessons ~6 min read Lesson 119

    CSRF & Form Security

    csrf & form security csrf and form security harden html forms with synchronizer tokens, post-only mut csrf and form security

    Course progress0%
    Focus
    18 guided sections
    Practice signal
    Examples included
    Career prep
    Interview Q&A included

    Introduction

    CSRF and form security protect state-changing HTML forms from cross-site request forgery — attackers trick authenticated users' browsers into submitting unwanted POST requests. OWASP recommends synchronizer tokens, SameSite cookies, and verifying Origin/Referer headers alongside semantic HTML form methods.

    Business problem

    CSRF on transfer, email change, or admin action endpoints causes financial loss without XSS — victim visits attacker page while logged in; hidden form auto-submits. HTML form semantics (method, action) and token placement matter.

    • OWASP A01: Broken access control includes CSRF on missing token validation.
    • API + cookie auth: SPAs using cookie sessions need CSRF tokens on mutating requests.

    Why this feature exists

    Browsers send cookies automatically on cross-origin form POST to same site — server must verify intent via unguessable token or SameSite=Strict/Lax cookie policy. HTML forms are the original CSRF vector predating fetch API.

    • GET mutations: Anti-pattern — CSRF via img src — ban state change on GET.
    • SameSite: Lax blocks most cross-site POST cookies; Strict stronger; None requires Secure.

    Browser internals

    Form submission navigates or fetches with credentials include for same-site cookies. Hidden input csrf token must be unpredictable per session — not in cookie alone (double-submit variant excepted with care).

    • autocomplete=off on token field optional — token not user password.
    • multipart: CSRF applies equally to file upload forms.

    Rendering workflow

    Secure form HTML: method=post for mutations, action to same origin HTTPS, hidden CSRF input from server session, enctype appropriate, no sensitive ops on GET links styled as buttons.

    • Double submit cookie: Token in cookie + header/body — must use __Host- prefix and Secure.
    • SPA: Meta tag csrf-token + fetch X-CSRF-Token header from readable cookie pattern.

    Feature deep dive

    Production HTML form security pattern (OWASP CSRF Prevention Cheat Sheet):

    • Token: Cryptographically random per session or request.
    • Validate: Server rejects missing/mismatch before business logic.
    • SameSite: Session cookie SameSite=Lax minimum.
    • Origin check: Supplement token with Origin/Referer validation.
    html
    <form action="/account/email" method="post" autocomplete="on">
    <input type="hidden" name="_csrf" value="{{ csrfToken }}">
    <label for="email">New email</label>
    <input id="email" name="email" type="email" required autocomplete="email">
    <button type="submit">Update email</button>
    </form>
    <!-- ❌ Never: <a href="/account/delete">Delete</a> without POST + token -->

    Accessibility analysis

    CSRF hidden fields should be aria-hidden from SR as decorative — not focusable. Use POST redirect after mutation with PRG pattern — screen reader users get clear success page.

    • autocomplete tokens: Don't confuse CSRF field with user autocomplete — distinct name _csrf.

    SEO impact

    Minimal SEO impact — ensure CSRF-protected admin forms are noindex. Public forms (newsletter) still need bot protection (honeypot) separate from CSRF for anonymous users.

    Security considerations

    OWASP CSRF defenses layered: Token required; SameSite cookies; re-auth for sensitive ops (password, payment); custom header on AJAX (not simple CORS request).

    • Login CSRF: Force victim into attacker's session — separate token on login form.

    Performance impact

    Per-request tokens prevent caching of form HTML page — acceptable for authenticated pages. Anonymous forms may use session-less double-submit with signed token.

    Real production example

    Express + csurf pattern (modern alternatives: custom middleware):

    • SPA: Issue token in cookie + require header on API POST.
    html
    app.get("/transfer", (req, res) => {
    res.render("transfer", { csrfToken: req.csrfToken() });
    });
    app.post("/transfer", csrfProtection, (req, res) => {
    // validate token before transfer logic
    });

    Enterprise usage

    Banks add step-up MFA on wire transfer even with valid CSRF token — defense in depth. PCI scope isolates payment form HTML to hardened subdomain.

    Common production failures

    CSRF token omitted on JSON API when Content-Type application/json bypassed SameSite in old browsers — fixed with custom header requirement. GET /api/delete?id= CSRF classic — changed to POST.

    Architecture review questions

    • All mutating forms use POST with CSRF token?
    • Session cookie SameSite=Lax or Strict?
    • No state-changing GET links?
    • Origin/Referer validated on sensitive endpoints?
    • Login and password change have CSRF + re-auth?

    Hands-on project

    Project: Add CSRF hidden field to HTML form; implement server validation; demonstrate blocked cross-origin POST with curl without token.

    Interview questions

    Explain CSRF attack step by step.(Advanced)

    Victim authenticated to bank.com with session cookie. Victim visits evil.com which contains hidden form POST to bank.com/transfer with attacker's account. Browser sends session cookie automatically. Server executes transfer without victim intent unless CSRF token validated.

    Follow-up: SameSite=Lax enough alone?

    CSRF protection for SPA with cookie auth?(Advanced)

    Double-submit cookie or synchronizer token in meta + X-CSRF-Token header on fetch mutations; SameSite=Lax session cookie; verify Origin; avoid cookie auth for pure API if possible — use token auth. Require custom header so simple form can't forge.

    Follow-up: JWT in localStorage CSRF risk?

    Why not use GET for delete action?(Intermediate)

    GET should be safe/idempotent — browsers, proxies, prefetchers, and img tags can trigger GET without user intent. CSRF via <img src='/delete?id=1'>. Use POST with token for all mutations.

    Follow-up: GraphQL CSRF differences?

    Try it yourself

    Edit the HTML, CSS, or JS panels — the preview updates as you type.

    Try it yourself

    Preview

    Summary

    CSRF and form security harden HTML forms with synchronizer tokens, POST-only mutations, SameSite cookies, and Origin validation per OWASP — essential whenever session cookies authenticate state-changing requests.

    Ready to mark this lesson complete?Track your journey across the entire course.