Cross-Origin Resource Sharing (CORS) is a security feature implemented by web browsers to manage how web pages request resources from different origins. An origin is defined by the combination of a URI scheme (protocol), hostname, and port number. CORS enables safe cross-origin requests and data transfers between web browsers and servers.
How CORS Works
When a web page requests a resource (such as an image, a script, or data) from a different origin, the browser sends an HTTP request with an Origin header to the server. The server then decides whether to allow or deny the request based on the Origin header and responds with the appropriate CORS headers.
CORS Headers
Access-Control-Allow-Origin: Specifies which origins are allowed to access the resource.
Example: Access-Control-Allow-Origin: * (allows all origins)
Example: Access-Control-Allow-Origin: https://example.com (allows only requests from https://example.com)
Access-Control-Allow-Methods: Specifies which HTTP methods are allowed when accessing the resource.
Example: Access-Control-Allow-Methods: GET, POST, PUT
Access-Control-Allow-Headers: Specifies which HTTP headers can be used when making the request.
Example: Access-Control-Allow-Headers: Content-Type, Authorization
Access-Control-Allow-Credentials: Indicates whether the response can be exposed when the credentials flag is true.
Example: Access-Control-Allow-Credentials: true
Access-Control-Max-Age: Specifies how long the results of a preflight request can be cached.
Example: Access-Control-Max-Age: 86400 (24 hours)
Preflight Requests
For certain types of requests (such as those using HTTP methods other than GET, or those that include custom headers), the browser sends an additional HTTP request, known as a preflight request, using the OPTIONS method. The server must respond to this preflight request with appropriate CORS headers indicating whether the actual request is safe to send.
Examples of CORS in Action
Example 1: Simple GET Request
A web page at https://example.com tries to fetch data from https://api.anotherdomain.com/data.
Request:http
GET /data HTTP/1.1
Host: api.anotherdomain.com
Origin: https://example.com
Response:http
HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://example.com
Content-Type: application/json
{ “data”: “This is the data” }
In this case, the server at https://api.anotherdomain.com allows requests from https://example.com by including the Access-Control-Allow-Origin header in the response.
Example 2: Preflight Request for a PUT Method
A web page at https://example.com tries to update data on https://api.anotherdomain.com/data using the PUT method.
Preflight Request: http
OPTIONS /data HTTP/1.1
Host: api.anotherdomain.com
Origin: https://example.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: Content-Type
Preflight Response: http
HTTP/1.1 204 No Content
Access-Control-Allow-Origin: https://example.com
Access-Control-Allow-Methods: PUT
Access-Control-Allow-Headers: Content-Type
Access-Control-Max-Age: 86400
Actual Request: http
PUT /data HTTP/1.1
Host: api.anotherdomain.com
Origin: https://example.com
Content-Type: application/json
{ “data”: “Updated data” }
Actual Response: http
HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://example.com
Content-Type: application/json
{ “data”: “Updated data” }
The preflight request checks if the PUT method and Content-Type header are allowed. The server responds affirmatively, allowing the actual PUT request to proceed.
Handling CORS on the Server
Different server-side technologies handle CORS in different ways. Here are some examples:
Node.js with Express
javascript
const express = require('express');
const cors = require('cors');
const app = express();
app.use(cors({
origin: 'https://example.com',
methods: ['GET', 'POST', 'PUT'],
allowedHeaders: ['Content-Type'],
credentials: true
}));
app.get('/data', (req, res) => {
res.json({ data: 'This is the data' });
});
app.listen(3000, () => {
console.log('Server is running on port 3000');
});
Flask (Python)
from flask import Flask, jsonify
from flask_cors import CORS
app = Flask(__name__)
CORS(app, origins="https://example.com")
@app.route('/data')
def get_data():
return jsonify(data='This is the data')
if __name__ == '__main__':
app.run()
ASP.NET Core
csharp
public void ConfigureServices(IServiceCollection services)
{
services.AddCors(options =>
{
options.AddPolicy("AllowSpecificOrigin",
builder => builder.WithOrigins("https://example.com")
.AllowAnyMethod()
.AllowAnyHeader()
.AllowCredentials());
});
services.AddControllers();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseCors("AllowSpecificOrigin");
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
Conclusion
CORS is a crucial mechanism for web security, enabling controlled access to resources across different origins while preventing malicious cross-site requests. By setting appropriate CORS headers, servers can specify which origins, methods, and headers are permitted, ensuring that only legitimate requests are processed.