Understanding CORS, CSRF, and CSP Once and for All
#webdev
#security
#tutorial
Introduction
Web applications often rely on multiple security models that protect users and data across different contexts. CORS, CSRF, and CSP are three such mechanisms that address different problems. This post explains what each one does, how they work together, and common pitfalls to avoid.
What is CORS and why it matters
Cross-Origin Resource Sharing (CORS) controls how browsers permit scripts from one origin to access resources on another origin. It prevents a malicious site from reading sensitive data from another site without permission.
Key points:
- CORS is implemented via HTTP headers like Access-Control-Allow-Origin and Access-Control-Allow-Credentials.
- Preflight requests (OPTIONS) check what is allowed before the actual request, especially for non-simple requests.
- Wildcard origins (*) can be convenient but are risky when requests include credentials.
Example:
Access-Control-Allow-Origin: https://example.com
Access-Control-Allow-Credentials: true
Access-Control-Allow-Methods: GET, POST, PUT, DELETE
Access-Control-Allow-Headers: Content-Type, Authorization
Access-Control-Max-Age: 3600
What is CSRF and how to defend against it
Cross-Site Request Forgery tricks a user’s browser into making unintended requests to a site where the user is authenticated. The attacker leverages the user’s session without the user’s knowledge.
Defenses:
- Use SameSite cookies to limit cross-site cookie sending.
- Require CSRF tokens for state-changing requests (e.g., POST, PUT, DELETE).
- Validate tokens on the server side and tie them to the user’s session.
- Avoid relying on Referer headers for CSRF protection, as they can be spoofed or blocked.
Example (simplified):
<form method="POST" action="/transfer">
<input type="hidden" name="csrf_token" value="TOKEN_VALUE">
<!-- other fields -->
<button type="submit">Submit</button>
</form>
// Server-side pseudocode
if (!validate_csrf_token(request.body.csrf_token, session)) {
return 403 Forbidden
}
What is CSP and why it matters
Content Security Policy (CSP) reduces the risk of Cross-Site Scripting (XSS) and other content-injection attacks by restricting what can be loaded and executed by the browser.
Core ideas:
- Define trusted sources for scripts, styles, images, etc.
- Prohibit inline scripts and styles unless explicitly allowed (via nonces or hashes).
- Use reporting to monitor violations without breaking the user experience.
Example:
Content-Security-Policy: default-src 'self'; script-src 'self' https://cdn.example.com; style-src 'self' 'unsafe-inline'; object-src 'none'; report-uri /csp-report
How CORS, CSRF, and CSP relate to each other
- CORS governs cross-origin access for resources. It’s about what a browser is allowed to fetch from another origin.
- CSRF protects against unauthorized actions performed leveraging an authenticated user’s session.
- CSP restricts what content the browser can execute or render, reducing XSS surface area.
They address different layers of a web app’s security: network-level access (CORS), request integrity (CSRF), and content integrity (CSP). Properly configuring all three reduces risk in complementary ways.
Common pitfalls and misconceptions
- Believing CORS protects against CSRF: they protect against different threats; both may be relevant but for different attack vectors.
- Using insecure CSP (e.g., allowing inline scripts globally) defeats the purpose.
- Using wildcard origins with credentials in CORS: this opens risky access patterns.
- Relying on client-side checks for CSRF: you must validate on the server side.
- Neglecting SameSite cookies: even with CSRF tokens, SameSite can add a helpful defense.
Practical patterns and best practices
-
CORS
- Allow only trusted origins and avoid wildcard when credentials are required.
- Use Access-Control-Allow-Credentials only if you truly need cookies or HTTP authentication.
- Send Vary: Origin to help caches distinguish responses.
- Prefer simple requests when possible to minimize preflight overhead.
-
CSRF
- Implement CSRF tokens for state-changing requests.
- Prefer SameSite=Lax or Strict cookies to reduce cross-site requests.
- Keep tokens per-session and rotate them periodically.
-
CSP
- Start with a strict default-src ‘self’ and explicitly add trusted sources.
- Disable inline scripts and styles unless you absolutely need them (use nonces or hashes if you must allow inline).
- Use a CSP reporting endpoint to monitor violations without breaking user experience.
- Regularly review and tighten the policy as the app evolves.
-
Quick-start checklist
- CORS: Restrict origins; avoid wildcards with credentials.
- CSRF: Enable CSRF tokens for state-changing endpoints; enable SameSite cookies.
- CSP: Implement a strict policy; use nonces/hashes for allowed inline or dynamic scripts.
- Monitoring: Enable CSP violation reporting; audit CORS and CSRF configurations periodically.
Quick-start references
- Sample CORS headers for a trusted API:
Access-Control-Allow-Origin: https://example.com
Access-Control-Allow-Credentials: true
Access-Control-Allow-Methods: GET, POST, PUT, DELETE
Access-Control-Allow-Headers: Content-Type, Authorization
- Sample CSRF token usage in a form:
<form method="POST" action="/transfer">
<input type="hidden" name="csrf_token" value="TOKEN_VALUE">
<!-- fields -->
<button type="submit">Submit</button>
</form>
// Server-side validation (conceptual)
if (!validate_csrf_token(request.body.csrf_token, session)) {
respond_with(403)
}
- Sample CSP policy:
Content-Security-Policy: default-src 'self'; script-src 'self' https://cdn.example.com; style-src 'self' 'unsafe-inline'; object-src 'none'; report-uri /csp-report
Conclusion
CORS, CSRF, and CSP each address distinct but complementary security concerns in modern web apps. By clearly understanding their roles and implementing sensible defaults, you can reduce cross-origin exposure, prevent unauthorized state-changing actions, and minimize the impact of content-based attacks. Treat these controls as layered protections rather than a single silver bullet, and keep monitoring and iteration a regular part of your security posture.