Why do we have both CSRF protection and CORS?
Historical origins & Same-Origin Policy
- Early web: cross-origin requests via
<img>,<form>,<frame>were a feature for linking and simple integrations (“search this site on Google”), not seen as a security risk. - Same-Origin Policy (SOP) emerged quickly after JavaScript as a fix; the model was “you can cause a request, but you usually can’t read cross-origin responses.”
- Inclusion of cross-origin
<script>was initially seen as safe/intentional: page authors explicitly chose the script, and data was expected to live in HTML/XML, not JS. - Security thinking in the 90s/early 00s was immature; many current threat models (drive-by impersonation, large-scale app security) did not dominate early design.
What CORS Actually Does
- Browsers still allow many cross-origin requests (forms, images, “simple” fetches); CORS only governs whether the calling origin can read the response and whether credentials may be sent.
- By default, JS can send cross-origin requests but can’t read non‑CORS responses; writes are often allowed, reads are blocked.
- Some argue CORS mainly protects IP‑based or private-network resources, not data exfiltration; others see it as a core privacy boundary for web apps.
- CORS is a browser-only enforcement; non-browser clients can ignore it and spoof
Origin.
CSRF vs CORS vs SameSite
- CSRF: server-side mechanism to prevent unauthorized state‑changing actions that rely on ambient credentials (cookies). Typical pattern: token tied to session and/or page, checked on write requests.
- SOP/CORS: prevent scripts on evil.com from reading bank.com, so they can’t steal CSRF tokens or other secrets.
- SameSite cookies now block many cross-site cookie sends by default, reducing CSRF risk without application logic, but CSRF tokens remain important for complex flows (e.g., OAuth
state). - Clarified threat: attacker can cause the browser to send cookies to bank.com, but cannot read bank.com responses or CSRF tokens if SOP/CORS are correct.
Cookies, Tokens, and Implementation Details
- Good practice: CSRF token distinct from session token; often stored in a non‑HttpOnly cookie or page content, with server-side or stateless validation.
- Debate on HttpOnly: still useful to block cookie theft via XSS; others note many modern SPAs need JS-accessible credentials and fall back to other storage.
- Frameworks can unintentionally re-enable CSRF vectors (e.g., auto-accepting HTML forms or broad content-types); some developers whitelist content types to avoid this.
- Question raised (unanswered in detail): why rotation of CSRF tokens is materially more secure than long-lived ones.
Browser Control, UX, and Diagnostics
- Some want per-request user overrides (“allow this cross-origin fetch”), but others argue prompts would be confusing, constant, and exploitable for phishing.
- There is frustration with opaque CORS/CSRF errors and poor tooling; debugging misconfigurations is described as painful.
- Service workers can intercept and alter request modes, further complicating mental models.
Limitations, Workarounds, and Criticisms
- CORS often blocks benign client-side access to public data, pushing developers to CORS proxies or backends.
- Wildcards and credentials interact poorly (
*disallows credentials); dynamicAccess-Control-Allow-Originand preflights add operational complexity. - Some see CORS as an “insecurity feature” that loosens SOP and is easy to bypass with custom clients; others insist domains remain a critical security boundary (for cookies, TLS, and SOP itself).
- Side-channel “XS-Leaks” show that, even without direct reads, attackers can infer cross-origin state via dimensions, errors, timing, etc.