In modern web development, ensuring secure and controlled communication between different origins (domains) is important. This is where Cross-Origin Resource Sharing (CORS) comes into play.
CORS is a fundamental security mechanism implemented by web browsers that governs how web pages from one origin can interact with resources from another.
In this article, we'll delve into the intricacies of CORS, demystify its inner workings, and explore how it safeguards the integrity and privacy of data exchanged across different web origins.
Understanding Cross-Origin Requests
Before delving into the specifics of CORS, let's establish a foundation of understanding about cross-origin requests.
Imagine a scenario where a web page hosted on http://localhost:4000/
wants to retrieve data from an API located at http://localhost:3000/data
. In a simpler time, this interaction might have raised concerns about data security and unauthorized access. CORS addresses these concerns by adding a layer of control and validation.
The image shows a cross-origin request by a web page froma different origin
The Role of CORS
CORS acts as a Gatekeeper: Think of CORS as a virtual gatekeeper stationed between web origins. When a cross-origin request is initiated, the gatekeeper evaluates whether the request is permissible or not.
Origin and Security: An origin is a combination of the protocol (HTTP or HTTPS), domain, and port. CORS ensures that only web pages from approved origins can access specific resources hosted on other domains.
Request with Origin Header: When a web page makes a request to an external resource, it includes an "Origin" header in the request. This header indicates the origin of the requesting web page.
Server Response with CORS Headers: The server that hosts the requested resource evaluates the incoming "Origin" header. If the server is configured to allow the requesting origin, it responds with CORS headers that provide permission details.
How CORS Works
1.Request with Origin Header: The requesting web page sends a request to a different domain, including an "Origin" header.
async function fetchData() {
try {
const response = await fetch('http://localhost:3000/data', {
method: 'GET',
headers: {
'Origin': ' http://localhost:4000'
}
});
const data = await response.json();
console.log(data);
} catch (error) {
console.error(error);
}
}
2.Server Response with CORS Headers: The server checks the "Origin" header against its allowed origins. If the request is authorized, the server responds with specific CORS headers that grant access.
app.get('/data', (req, res) => {
const allowedOrigins = ['http://localhost:4000', 'https://otherdomain.com'];
const requestOrigin = req.headers.origin;
if (allowedOrigins.includes(requestOrigin)) {
res.header('Access-Control-Allow-Origin', requestOrigin);
res.header('Access-Control-Allow-Methods', 'GET');
res.status(200).json({ data: 'Response data' });
} else {
res.status(403).json({ error: 'Unauthorized origin' });
}
});
3.Browser Check and Access Decision: The browser receives the response along with CORS headers. It verifies that the requesting origin matches the allowed origins specified in the "Access-Control-Allow-Origin" header. If they match, the browser allows access.
async function fetchData() {
try {
const response = await fetch('http://localhost:3000/data');
const data = response.json();
} catch (error) {
console.error(error);
}
}
4.Blocking Unauthorized Access: If the requested origin is not in the approved list or if CORS headers are missing, the browser blocks the response from being accessed. This shields the data from unauthorized access.
Pre-Fight Requests
Preflight requests are an essential part of the Cross-Origin Resource Sharing (CORS) mechanism and are used by browsers to check with the server whether a specific cross-origin request is allowed.
Preflight requests are automatically triggered by the browser under certain conditions before the actual request is made. They ensure that the server is properly configured to handle the cross-origin request.
Here's how preflight requests work in CORS:
1.Complex Requests: Preflight requests are primarily used for so-called "complex" requests. A request is considered complex if it meets any of the following criteria:
- It uses an HTTP method other than GET, HEAD, or POST.
- It sets custom headers using the
setRequestHeader()
method. - It sends data other than simple textual data (e.g., JSON, XML) as the request body.
2.Preflight Request: When the browser detects that a cross-origin request is complex, it automatically sends a preflight OPTIONS request to the server before sending the actual request. This preflight request includes the following headers:
-
Origin
: The origin of the requesting site. -
Access-Control-Request-Method
: The HTTP method of the actual request. -
Access-Control-Request-Headers
: A list of any custom headers used in the request.
3.Server Response: The server should be configured to respond to preflight requests with appropriate CORS headers. These headers inform the browser whether the actual request is allowed. The relevant headers are:
-
Access-Control-Allow-Origin
: Specifies which origins are allowed to access the resource. This header must match the origin of the requesting site or be set to*
to allow any origin. -
Access-Control-Allow-Methods
: Specifies the HTTP methods that are allowed for the actual request. -
Access-Control-Allow-Headers
: Specifies the custom headers that are allowed for the actual request.
4. Browser Decision: Based on the response from the server's preflight request, the browser decides whether to proceed with the actual request. If the server responds with appropriate headers indicating that the actual request is allowed, the browser sends the actual request. If the server does not provide the necessary headers or explicitly denies the request, the browser generates a CORS error and does not send the actual request.
5.Actual Request: If the preflight request is successful, the browser sends the actual request to the server with the appropriate headers. The server processes the request and responds to it.
It's important to note that the preflight process adds an extra layer of security by ensuring that servers explicitly allow cross-origin requests and specify the allowed methods and headers. This helps protect against unauthorized access and potential security vulnerabilities.
When setting up CORS on your server, ensure that your server correctly handles preflight OPTIONS requests and responds with the appropriate CORS headers to indicate which origins, methods, and headers are allowed for the actual requests.
Conclusion
In conclusion, CORS acts as a gatekeeper that enforces rules for cross-origin requests, ensuring that only authorized origins can access resources hosted on different domains.
By understanding how CORS functions and its critical role in maintaining a secure web environment, developers can navigate the complexities of cross-origin communication with confidence.
As web applications continue to evolve and interconnect, CORS remains a steadfast guardian that enables secure data exchange while upholding the principles of privacy and integrity.
Top comments (3)
I noticed you tried to set the Origin header in your fetch command. This is ignored since Origin is a forbidden header (developer.mozilla.org/en-US/docs/G...). Only the browser can set forbidden headers. This makes sense otherwise malicious javascript could bypass CORS.
Thanks
This is really insightful 💡I now have a better understanding of CORS