Skip to content

CSRF, XSS and CORS

These three acronyms turn up together and are routinely swapped for one another. Two of them name attacks. The third names a way for a server to relax a protection the browser already enforces, which is the opposite of what its name suggests to most people.

A malicious page causes a visitor’s already-authenticated browser to perform an unwanted action on another site, by exploiting the fact that the browser attaches the target site’s cookies to the request automatically. The attacker never reads the response and does not need JavaScript — a form submission or an image tag is enough. The defences are a per-session anti-CSRF token that the attacker’s page cannot read, and SameSite cookie attributes.

Attacker-supplied script runs inside a legitimate origin, with that origin’s privileges: it can read the DOM, read any cookie not marked HttpOnly, and issue requests as the logged-in user. It arrives through input that is rendered back to a page without contextual output encoding — reflected from the request, stored in a database, or written into the DOM by client-side code. The defence is contextual encoding at the point of output, plus a Content Security Policy as a second line. See Secure coding.

CORS is not a defence. The browser’s same-origin policy is what stops one site reading another site’s responses; it applies whether or not the server knows anything about CORS. CORS is the mechanism by which a server opts in to relaxing that restriction, naming the origins it is willing to let read its responses. Widening a CORS policy removes protection; it never adds any.

Two consequences follow. A permissive Access-Control-Allow-Origin: * on an endpoint that returns anything user-specific is a data-exposure bug, not a convenience. And CORS does nothing against CSRF: a forged request does not need to read the response, and simple requests are sent to the server before any CORS check happens.

TermNeeds JavaScript?Relies on cookies?What it does
CSRFNoYesPerforms an action as the victim
XSSYesOftenRuns attacker code in the site’s origin
CORSNot an attackNoRelaxes the same-origin policy