Understanding CORS Policy: A Detailed Guide
Introduction to CORS
Cross-Origin Resource Sharing (CORS) is a critical security mechanism implemented by web browsers to control how web pages in one domain can make requests to another domain. As web applications become increasingly complex and distributed, understanding CORS is essential for developers to create secure and functional web services.
What is CORS?
CORS is a browser security feature that restricts web pages from making requests to a different domain than the one serving the web page. This mechanism prevents malicious websites from making unauthorized requests to your API or server, protecting users from potential cross-site scripting (XSS) and other security vulnerabilities.
Why is CORS Necessary?
By default, web browsers follow the Same-Origin Policy, which prevents web pages from making requests to a different domain. While this policy enhances security, it also limits the functionality of modern web applications that often need to interact with multiple services and APIs. CORS provides a controlled way to relax these restrictions, allowing servers to specify:
- Which origins can access their resources
- What HTTP methods are permitted
- What headers can be included in cross-origin requests
The Role of Preflight Requests in CORS
A preflight request is a special type of HTTP OPTIONS
request that browsers automatically send before making a complex cross-origin HTTP request. It acts as a preliminary “permission check” to determine whether the actual request is safe to send.
How Preflight Requests Work
-
Initial Check: The browser sends an
OPTIONS
request to the target server with two key headersAccess-Control-Request-Method
andAccess-Control-Request-Headers
. -
Server Response: The server responds with CORS headers indicating:
- Allowed origins
- Permitted HTTP methods
- Allowed headers
- Caching duration for preflight results
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# Preflight Request
OPTIONS /api/data HTTP/1.1
Host: api.example.com
Origin: https://webapp.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: Content-Type, Authorization
# Server Response
HTTP/1.1 204 No Content
Access-Control-Allow-Origin: https://webapp.com
Access-Control-Allow-Methods: PUT, GET, POST
Access-Control-Allow-Headers: Content-Type, Authorization
Access-Control-Max-Age: 86400
CORS Headers: A Detailed Breakdown
- Access-Control-Allow-Origin
- Specifies which origins are permitted to access the resource
- Can be a specific domain or * for all origins (not recommended for production)
1 2 3 4
# Allow a specific domain to access the resource Access-Control-Allow-Origin: yourdomain.com # Or for all origins Access-Control-Allow-Origin: *
- Access-Control-Allow-Methods
- Defines the HTTP methods allowed when accessing the resource
- Crucial for controlling the types of requests permitted
1 2
# Defines which methods are allowed to access Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS
- Access-Control-Allow-Headers
- Specifies which HTTP headers can be used in the actual request
- Important for custom headers or specific authentication mechanisms
1
Access-Control-Allow-Headers: Content-Type, Authorization, X-Requested-With
- Access-Control-Allow-Credentials
- Indicates whether the response to the request can be exposed when the credentials flag is true
- Required when sending cookies or authentication headers in cross-origin requests
1 2
# Required to pass authentication headers for secured resources Access-Control-Allow-Credentials: true
- Access-Control-Expose-Headers
- Lists headers that the browser is allowed to access from the response
1
Access-Control-Expose-Headers: X-Custom-Header, Content-Length
- Lists headers that the browser is allowed to access from the response
- Access-Control-Max-Age
- Specifies how long the results of a preflight request can be cached
- Reduces the number of preflight requests for the same resource
1
Access-Control-Max-Age: 86400
Full Nginx Configuration for CORS setup
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
server {
listen 80;
server_name example.com;
# Enable CORS for all locations
location / {
# Preflight requests handling
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, PUT, POST, DELETE, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'Content-Type, Authorization, X-Requested-With';
add_header 'Access-Control-Max-Age' 86400;
return 204;
}
# Regular CORS headers
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, PUT, POST, DELETE, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'Content-Type, Authorization, X-Requested-With';
}
}
Best Practices
- Always specify exact origins instead of using
*
- Use the least permissive CORS configuration possible
- Implement proper authentication and authorization
- Use HTTPS to encrypt cross-origin communications
- Regularly audit and update CORS policies