Cross-Origin Resource Sharing (CORS)
What is Cross-Origin Resource Sharing (CORS)?
Cross-Origin Resource Sharing (CORS) is a security mechanism that allows web applications running on one domain to access resources from another domain. CORS extends and relaxes the Same-Origin Policy (SOP) by enabling servers to specify who can access their resources and which HTTP methods are allowed.
CORS works by adding HTTP headers that instruct browsers to give web applications from different origins access to selected resources. This is essential for modern web applications that often need to interact with APIs and services hosted on different domains.
How CORS Works
CORS operates through a series of HTTP headers exchanged between the browser and server:
- Browser sends preflight request (for certain types of requests)
- Server responds with CORS headers
- Browser evaluates the headers and decides whether to allow the request
- If allowed, browser makes the actual request
Simple vs. Preflight Requests
Simple requests (no preflight needed):
- Use GET, HEAD, or POST methods
- Only allow specific headers (Accept, Accept-Language, Content-Language, Content-Type)
- Content-Type limited to:
application/x-www-form-urlencoded,multipart/form-data, ortext/plain
Preflight requests (require OPTIONS request first):
- Use PUT, DELETE, or other methods
- Include custom headers
- Have Content-Type other than simple types
Key CORS Headers
Request Headers
Origin: Indicates the origin of the requesting siteAccess-Control-Request-Method: Used in preflight requests to specify the methodAccess-Control-Request-Headers: Used in preflight requests to specify headers
Response Headers
Access-Control-Allow-Origin: Specifies which origins are allowedAccess-Control-Allow-Methods: Lists allowed HTTP methodsAccess-Control-Allow-Headers: Lists allowed request headersAccess-Control-Allow-Credentials: Indicates if credentials can be includedAccess-Control-Expose-Headers: Lists response headers that can be accessedAccess-Control-Max-Age: Specifies how long preflight response can be cached
Header Syntax and Examples
Basic CORS response:
Access-Control-Allow-Origin: https://example.com
Multiple allowed origins:
Access-Control-Allow-Origin: https://example.com, https://trusted-site.com
Allow all origins (not recommended for sensitive data):
Access-Control-Allow-Origin: *
Allow credentials (cookies, auth headers):
Access-Control-Allow-Credentials: true
Specify allowed methods:
Access-Control-Allow-Methods: GET, POST, PUT, DELETE
Specify allowed headers:
Access-Control-Allow-Headers: Content-Type, Authorization
Security Implications
Benefits of CORS:
- Enables secure cross-origin requests
- Provides granular control over resource access
- Maintains security while allowing necessary cross-origin interactions
- Prevents unauthorized access to sensitive data
Potential risks:
- Misconfiguration can expose sensitive data
- Overly permissive policies can enable CSRF attacks
- Wildcard (
*) origins should be avoided for sensitive operations - Credentials require careful handling
Best Practices
- Be specific with allowed origins - avoid using
*for sensitive data - Use credentials carefully - only enable when necessary
- Limit allowed methods to only what's required
- Restrict allowed headers to essential ones
- Set appropriate cache durations for preflight responses
- Combine with other security headers:
Example Implementations
Node.js (Express) Example:
app.use((req, res, next) => {
res.header('Access-Control-Allow-Origin', 'https://example.com');
res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE');
res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization');
res.header('Access-Control-Allow-Credentials', 'true');
next();
});
// Handle preflight requests
app.options('*', (req, res) => {
res.header('Access-Control-Max-Age', '86400'); // Cache for 24 hours
res.sendStatus(204);
});
Apache (.htaccess) Example:
Header set Access-Control-Allow-Origin "https://example.com"
Header set Access-Control-Allow-Methods "GET, POST, PUT, DELETE"
Header set Access-Control-Allow-Headers "Content-Type, Authorization"
Header set Access-Control-Allow-Credentials "true"
Header set Access-Control-Max-Age "86400"
Nginx Example:
location / {
add_header 'Access-Control-Allow-Origin' 'https://example.com';
add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE';
add_header 'Access-Control-Allow-Headers' 'Content-Type, Authorization';
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Access-Control-Max-Age' '86400';
if ($request_method = 'OPTIONS') {
return 204;
}
}
Common Use Cases
- API access: Allowing web applications to access APIs hosted on different domains
- Single Page Applications (SPAs): Loading resources from CDNs while accessing backend APIs
- Microservices architecture: Enabling communication between services on different domains
- Third-party integrations: Securely accessing external services and resources
- Content delivery: Loading fonts, scripts, and stylesheets from CDNs
- Authentication flows: Handling cross-origin authentication with credentials
CORS vs. JSONP
| Feature | CORS | JSONP |
|---|---|---|
| Security | More secure (built-in browser support) | Less secure (relies on script injection) |
| Error Handling | Proper HTTP status codes | Limited error handling |
| Request Types | Supports all HTTP methods | Only GET requests |
| Data Formats | Supports JSON, XML, etc. | Only JSON |
| Credentials | Supports cookies and auth headers | No credential support |
| Browser Support | Modern browsers | Legacy browser support |
Debugging CORS Issues
Common CORS errors and solutions:
- No 'Access-Control-Allow-Origin' header:
- Ensure server is sending the CORS headers
- Verify the origin is included in allowed origins
- Preflight request fails:
- Check that OPTIONS method is handled
- Verify allowed methods and headers
- Credentials not working:
- Ensure
Access-Control-Allow-Credentials: trueis set - Avoid using wildcard (
*) with credentials
- Ensure
- Method not allowed:
- Verify the HTTP method is included in
Access-Control-Allow-Methods
- Verify the HTTP method is included in
- Header not allowed:
- Ensure custom headers are listed in
Access-Control-Allow-Headers
- Ensure custom headers are listed in
Advanced CORS Features
Dynamic Origin Handling:
app.use((req, res, next) => {
const allowedOrigins = ['https://example.com', 'https://trusted-site.com'];
const origin = req.headers.origin;
if (allowedOrigins.includes(origin)) {
res.header('Access-Control-Allow-Origin', origin);
}
res.header('Access-Control-Allow-Credentials', 'true');
next();
});
CORS with Authentication:
app.use((req, res, next) => {
res.header('Access-Control-Allow-Origin', 'https://example.com');
res.header('Access-Control-Allow-Credentials', 'true');
res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization');
if (req.method === 'OPTIONS') {
res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE');
return res.status(204).send();
}
next();
});
Related Security Concepts
Cross-Origin Opener Policy (COOP)
HTTP security header that controls how documents can interact with cross-origin windows to prevent security vulnerabilities.
Cross-Site Request Forgery (CSRF)
Cross-Site Request Forgery (CSRF) is a web security vulnerability that tricks users into executing unwanted actions on a web application where they are authenticated, exploiting the trust a site has in a user browser.
