Understanding Cross-Origin Resource Sharing (CORS)
Web browsers enforce the Same-Origin Policy (SOP) to prevent malicious websites from accessing resources on other domains. Cross-Origin Resource Sharing (CORS) is a security mechanism that relaxes this restriction in a controlled way. By using HTTP headers, servers can explicitly define which external domains may access their resources, enabling secure cross-domain interactions while mitigating risks.
How CORS Works
CORS operates through a handshake between the browser and server. When a web application requests a resource from a different origin, the browser checks the server’s CORS headers to determine whether the request is permitted. If the headers allow the origin, the browser proceeds; otherwise, it blocks the request.
Key Principle: CORS shifts security responsibility from the browser to the server, allowing developers to define granular access policies.
Core HTTP Headers in CORS
| Header | Purpose | Example Value |
|---|---|---|
Access-Control-Allow-Origin | Specifies which origins can access the resource. Use * for public resources or a specific domain. | https://example.com or * |
Access-Control-Allow-Methods | Lists allowed HTTP methods (e.g., GET, POST, PUT). | GET, POST, OPTIONS |
Access-Control-Allow-Headers | Defines which request headers are permitted. | Content-Type, Authorization |
Access-Control-Max-Age | Caches preflight responses to reduce overhead (in seconds). | 86400 (24 hours) |
Access-Control-Allow-Credentials | Allows cookies or authentication headers in cross-origin requests. Requires true and explicit origins. | true |
Types of CORS Requests
Simple Requests
Browsers send simple requests without preflight checks if they meet all criteria:
- Use
GET,HEAD, orPOSTmethods. - Only include CORS-safelisted headers (e.g.,
Accept,Content-Type). Content-Typeis one of:application/x-www-form-urlencodedmultipart/form-datatext/plain
Example:
GET /api/data HTTP/1.1
Host: api.example.com
Origin: https://client.example.com
Preflight Requests
For "non-simple" requests (e.g., PUT, DELETE, or custom headers), browsers first send an OPTIONS request to verify CORS compliance.
Example Preflight Flow:
- Browser sends:
OPTIONS /api/data HTTP/1.1 Origin: https://client.example.com Access-Control-Request-Method: PUT Access-Control-Request-Headers: X-Custom-Header - Server responds with allowed methods/headers:
HTTP/1.1 204 No Content Access-Control-Allow-Origin: https://client.example.com Access-Control-Allow-Methods: PUT, POST Access-Control-Allow-Headers: X-Custom-Header
Common Use Cases
- APIs: Securely expose endpoints to third-party clients (e.g.,
https://api.example.comaccessed byhttps://app.client.com). - CDNs: Serve static assets (e.g., images, fonts) from a different domain.
- Single Sign-On (SSO): Share authentication tokens across subdomains (e.g.,
auth.example.comandapp.example.com). - Microservices: Enable communication between services hosted on separate domains.
Security Risks and Misconfigurations
Critical Pitfalls
-
Wildcard Overuse: Using
Access-Control-Allow-Origin: *with credentials (Access-Control-Allow-Credentials: true) exposes sensitive data.Fix: Always specify exact origins when credentials are involved.
-
Null Origin Abuse: Accepting
Origin: null(e.g., from local files or sandboxed iframes) can lead to attacks.Fix: Explicitly block
nullorigins or restrict them to trusted contexts. -
Regex Vulnerabilities: Poorly crafted regex for origin validation (e.g.,
.*\.example\.com) can be bypassed via subdomains likeattacker.example.com.Fix: Use exact string matching or a whitelist of allowed domains.
-
Dynamic Origin Reflection: Echoing the
Originheader without validation (e.g.,Access-Control-Allow-Origin: $origin) allows any domain to access resources.Fix: Validate origins against a predefined list.
Best Practices
- Restrict Origins: Use specific domains instead of wildcards for sensitive resources.
- Limit Methods/Headers: Only allow necessary HTTP methods and headers.
- Short Cache Durations: Set
Access-Control-Max-Ageto a reasonable value (e.g., 5 minutes) to reduce preflight overhead. - Test Configurations: Use tools like CORS Tester to validate headers.
- Monitor Logs: Audit CORS-related errors in server logs to detect misconfigurations.
Debugging CORS Issues
Symptoms:
- Browser console errors like
No 'Access-Control-Allow-Origin' headerorPreflight response did not succeed. - Requests blocked despite correct server headers.
Troubleshooting Steps:
- Verify the
Originheader matches the allowed domains. - Check for typos in header names (e.g.,
Access-Control-Allow-Originvs.Access-Control-AllowOrigins). - Ensure the server responds with
200 OKor204 No Contentfor preflight requests. - Confirm the server supports
OPTIONSrequests.
Learn More
- MDN Web Docs: CORS – Official reference with examples.
- OWASP CORS Cheat Sheet – Security-focused guidelines.
- Google’s CORS Guide – Practical implementation tips.