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); dynamic Access-Control-Allow-Origin and 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.