Exercise 3: Origin-Header Protection vs. a CSRF Token — Possible Solution ==================================================================== WHAT A CSRF TOKEN LIKE {% csrf_token %} ACTUALLY DEFENDS AGAINST ------------------------------ A malicious site tricks a logged-in user's own browser into submitting a form to a different site (the real, trusted one) without the user's knowledge. Django's {% csrf_token %} embeds a secret, unpredictable value into the real form; the malicious site's own forged form has no way to know or include that value, so the server rejects the forged submission while accepting the real one. WHAT THE ORIGIN-HEADER CHECK DEFENDS AGAINST ------------------------------ Per this chapter, a Server Action call carries a real, unforgeable Origin header set by the browser itself, not by the page's own JavaScript - identifying which site actually initiated the request. A malicious site attempting to trigger updatePageTitle would have its own Origin (the malicious site's own domain), not the real deployment's domain. Next.js compares the two and rejects the call the moment they don't match, before updatePageTitle's own code ever runs. WHY BOTH ACHIEVE THE SAME GOAL DIFFERENTLY ------------------------------ Both mechanisms exist to answer the identical question - "did this request genuinely originate from a page this application itself served, or from somewhere else pretending to submit on the user's behalf?" A CSRF token answers it by embedding a shared secret the real page knows and a forged one can't guess. The Origin-header check answers it by trusting a value the browser itself sets and a forged request can't spoof, with no secret value needing to be generated, embedded, or checked anywhere in application code at all. WHY THIS WORKS AS AN ANSWER ------------------------------ It correctly identifies the actual threat both mechanisms defend against (a forged cross-site submission, not a listed technical mismatch), and correctly explains why the Origin-header approach achieves the identical protective outcome through a genuinely different mechanism - trusting a browser-set header rather than a server-generated secret - rather than just noting "there's no visible token" without explaining what does the equivalent job instead.