DEV Community

Marco
Marco

Posted on • Originally published at blog.disane.dev

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.

Preview image

🔍 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.

Season 5 Idk GIF by The Office

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:

  1. **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.
  2. Access-Control-Allow-Methods: This header specifies the HTTP methods that the server allows for cross-origin requests (e.g. GET, POST).
  3. 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.

Movie gif. Mark Wahlberg as Elliot in The Happening stares ahead as his eyes glances around in confusion.

An example of a preflight request:

Advantages of CORS ✅

  1. 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.
  2. 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.
  3. 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 ❌

  1. 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.
  2. Performance losses: Each CORS request must be validated by the server, which can easily affect performance, especially if many requests are processed simultaneously.
  3. 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:

  1. 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.
  2. 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.
  3. 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:

  1. Allow specific origins: Allow only specific domains instead of allowing all origins (*). This increases security considerably.
  2. 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.
  3. 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 trueAccess-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:

  1. Allow specific origins: Use a whitelist for trusted origins instead of wildcards. This significantly reduces the attack surface.
  2. Specify exact headers: Be precise when specifying the permitted methods and headers. It is better to be more restrictive to avoid potential security vulnerabilities.
  3. Handle preflight requests correctly: Make sure your server responds correctly to OPTIONS requests and returns the correct headers.

You Rock GIF by iFLY Indoor Skydiving

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"
}

Enter fullscreen mode Exit fullscreen mode

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

Enter fullscreen mode Exit fullscreen mode

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

Enter fullscreen mode Exit fullscreen mode

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:

Preview image

and an explanation of how REST APIs work:

Preview image

or GraphQL works:

Preview image

Discuss in the comments below if you have ever encountered CORS problems and how you solved them!


If you like my posts, it would be nice if you follow my Blog for more tech stuff.

Top comments (0)