CORS (Cross-Origin Resource Sharing) π
Understand the importance of CORS for secure web applications. Learn the pros and cons and how to avoid common mistakes! π
CORS, or Cross-Origin Resource Sharing, is a security mechanism used by web browsers to control which web applications are allowed to request resources from another domain. Although CORS has been a standard for many years, many developers, especially beginners, find it difficult to understand. This article aims to explain CORS comprehensively, highlight the most common pitfalls and provide helpful implementation tips.
What is CORS and why is it necessary? π€
To understand why CORS exists, it is important to first understand the so-called Same-Origin-Policy (SOP) principle. The same-origin policy is a security rule that prevents a document or script originating from one source (domain, protocol and port) from accessing resources from another source. This rule protects against malicious attacks in which malicious websites could steal data from another origin.
A simple example:
You are logged in to example.com
and logged in to a page on this domain. Without CORS or same-origin policy, another malicious website, say badsite.com
, could try to send a request to example.com
to grab your sensitive data.
π What happens without CORS?
Without CORS, the browser would block such a request to protect you. This leads us to the problem that sometimes legitimate requests from another domain are also blocked, leading to limitations in the development of modern web applications.
This is where CORS comes into play. CORS allows a server to release resources for requests from certain origins while blocking others. This is achieved through special HTTP headers that the server sends when responding to a request.
The-functionality-of-cors π οΈ
To understand, how CORS works, we need to take a closer look at the different headers that can be sent by a server. The most important headers that come into play in a CORS request are:
Access-Control-Allow-Origin
: This header specifies which origins have access to the server's resources. For example:Access-Control-Allow-Origin: https://example.com
.Access-Control-Allow-Methods
: This header specifies the HTTP methods that the server allows for cross-origin requests (e.g. GET, POST).Access-Control-Allow-Headers
: This header lists the permitted HTTP headers that can be sent by the request.
Preflight requests
An important component of CORS is the so-called preflight request. This occurs when a request uses a method that does not fall into the "safe" category (e.g. POST, PUT) or contains special headers. Before the actual request is sent, the browser sends an OPTIONS request to the server to check whether the actual request is permitted.
An example of a preflight request:
Advantages of CORS β
- Security: The biggest advantage of CORS is the increased security. It prevents malicious websites from accessing resources from another domain, which protects data privacy and integrity.
- Controlled access: CORS allows servers to determine exactly which resources may be requested from which origins (domains). This gives developers control over who can access their APIs.
- Support for modern web applications: At a time when single-page applications and microservices are becoming increasingly common, CORS is essential. It allows web applications to communicate seamlessly with multiple APIs hosted on different domains.
Disadvantages of CORS β
- Complexity: Implementing CORS can be complicated, especially for developers who don't fully understand how it works. Incorrect configurations often lead to problems such as blocked requests and error messages in the browser.
- Performance losses: Each CORS request must be validated by the server, which can easily affect performance, especially if many requests are processed simultaneously.
- Lack of support for older browsers: Although CORS is supported by modern browsers, older versions may have compatibility issues.
Common misunderstandings and problems with CORS π§
Many developers encounter difficulties when implementing CORS because they don't fully understand how it works. Here are some common misconceptions:
- CORS is a client-side technology: A common misconception is that CORS is driven from the client side. However, CORS is actually configured on the server side. The server determines whether a request from another domain is accepted or not.
- Simply enabling it is not enough: It is not enough to simply enable CORS on the server. Developers must ensure that the correct headers are set and that only the desired origins are allowed.
- Faulty preflight requests: Preflight requests are a part of CORS where the browser first checks whether the server will accept the actual request. If these preflight requests fail, the entire request fails.
Best practices for implementing CORS π οΈ
To avoid problems with CORS, developers should follow some best practices:
- Allow specific origins: Allow only specific domains instead of allowing all origins (
*
). This increases security considerably. - Understanding preflight requests: Preflight requests are often misunderstood. They are used to ensure that the server allows the requests. Developers should ensure that their server responds correctly to these requests.
- Using
Access-Control-Allow-Origin
: This header is the key to controlling CORS. It should be set carefully to allow the desired origins.
Important CORS headers π οΈ
Header | Description |
---|---|
Access-Control-Allow-Origin | Specifies which origins (domains) are allowed to access the resources. Example: https://example.com . |
Access-Control-Allow-Methods | Lists the HTTP methods that are permitted for cross-origin requests (e.g.e.g. GET, POST, PUT, DELETE). |
Access-Control-Allow-Headers | Lists the HTTP headers that may be sent in the request (e.g. Content-Type, Authorization). Content-Type, Authorization). |
Access-Control-Allow-Credentials | Indicates whether cookies and other credentials may be sent as part of the request. |
Access-Control-Expose-Headers | Defines which headers in the response are visible to the JavaScript code on the client side. |
Access-Control-Max-Age | Specifies the duration in seconds for which the results of the preflight request are stored in the browser's cache. |
Access-Control-Request-Method | This header is sent by the browser in the preflight request to specify the intended HTTP method (e.g. POST). |
This header is sent by the browser in the preflight request to specify the intended HTTP method (e.g. POST).e.g. POST). | |
Access-Control-Request-Headers | Is also sent by the browser in the preflight request to specify the HTTP headers to be used. |
Detailed explanation of the CORS headers π
Access-Control-Allow-Origin
This header is the most important in the CORS implementation. It specifies which origins (domains) may have access to the server's resources. For example, if you only want requests from https://example.com
to be allowed, set this header as follows: Access-Control-Allow-Origin: https://example.com
. A common misconception is the use of *
, which means that all origins are allowed. Although this is simple, it can be a security risk.
Access-Control-Allow-Methods
This header lists the HTTP methods that the server allows for cross-origin requests. Typical methods are GET, POST, PUT and DELETE. For example, the header could look like this: Access-Control-Allow-Methods: GET, POST
. It is important to only allow the methods that are actually required in order to minimize the security risk.
Access-Control-Allow-Headers
If the request requires additional headers such as Content-Type
or Authorization
, the server must explicitly allow these. This header defines which headers may be present in the request. An example would be: Access-Control-Allow-Headers: Content-Type, Authorization
. This allows the server to allow specific headers that are necessary for the request.
Access-Control-Allow-Credentials
This header specifies whether the browser is allowed to send credentials (such as cookies or HTTP-Auth data) with the request. For example, if the server wants to set a cookie, this header must be set to true
Access-Control-Allow-Credentials: true. It is important to note that this header is used in combination with Access-Control-Allow-Origin
, whereby the value of Access-Control-Allow-Origin
must not be *
.
Access-Control-Expose-Headers
By default, not all HTTP headers in the response are visible to JavaScript in the browser. This header defines which headers in the response are visible to the client. If you want the client to be able to access a special header such as X-Custom-Header
, you would set this header as follows: Access-Control-Expose-Headers: X-Custom-Header
.
Access-Control-Max-Age
This header specifies how long (in seconds) the results of a preflight request may be stored in the browser's cache. For example, the header could look like this: Access-Control-Max-Age: 86400
, which means that the response may remain in the cache for 24 hours. This can improve performance, as preflight requests do not have to be resent for a certain period of time.
Access-Control-Request-Method
This header is sent by the browser for a preflight request and specifies which HTTP method the actual request will use, e.g. POST or GET. The server then checks whether this method is permitted.
Access-Control-Request-Headers
This header is also sent by the browser for a preflight request. It specifies the HTTP headers that are to be used in the actual request, e.g. Content-Type
. The server then checks whether these headers are allowed.
By understanding these headers and their functions, developers can ensure that their web applications can communicate correctly and securely with different origins.
How CORS is implemented correctly π οΈ
Correctly implementing CORS requires a good understanding of headers and how HTTP requests work. Here are some best practices:
- Allow specific origins: Use a whitelist for trusted origins instead of wildcards. This significantly reduces the attack surface.
- Specify exact headers: Be precise when specifying the permitted methods and headers. It is better to be more restrictive to avoid potential security vulnerabilities.
- Handle preflight requests correctly: Make sure your server responds correctly to OPTIONS requests and returns the correct headers.
Examples from practice π₯οΈ
To illustrate how CORS works in practice, here is a simple example:
Simple GET request
Imagine you build a website at https://mywebsite.com
that retrieves data from an API on https://api.example.com
. The server on https://api.example.com
must configure CORS to allow requests from https://mywebsite.com
.
HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://mywebsite.com
Content-Type: application/json
{
"message": "Successfully retrieved"
}
In this case, the browser receives the data because the server has allowed the origin https://mywebsite.com
.
POST request with preflight
Suppose you want to send data to https://api.example.com
. As this is a non-secure method (POST), the browser will first send a preflight request.
Preflight request:
OPTIONS /data
Host: api.example.com
Access-Control-Request-Method: POST
Access-Control-Request-Headers: Content-Type
Origin: https://mywebsite.com
Response from the server:
HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://mywebsite.com
Access-Control-Allow-Methods: POST
Access-Control-Allow-Headers: Content-Type
Conclusion π
CORS is an essential technology for modern web development that brings both security benefits and challenges. It can be difficult for beginners to implement CORS properly, but with the right knowledge and some best practices, you can avoid common pitfalls. It's important that you familiarize yourself with the basics of CORS and know how to implement it properly to ensure both the security and functionality of your web applications.
This makes it possible for only one frontend (from a specific domain) to access certain parts of the API and nothing else. Especially with regard to API development, it is all the more important to really understand CORS. If you want to develop your own API, here's a little guide for you:
and an explanation of how REST APIs work:
or GraphQL works:
Discuss in the comments below if you have ever encountered CORS problems and how you solved them!