Table of contents of the article:
In the modern world of the web, security is a major concern for developers and system administrators. One of the security features that is often underestimated but is fundamental is that of CORS, or Cross-Origin Resource Sharing. This functionality is particularly relevant for companies that deal with hosting and systems engineering, especially those that use web servers like NGINX. In this article, we will explore in detail what HTTP header-level CORS are and what they are used for, with a particular focus on how to implement them in an NGINX environment.
What is CORS?
CORS, an acronym for "Cross-Origin Resource Sharing", is a web security protocol implemented in modern browsers to control and manage resource requests between different web domains. In simpler terms, CORS is a set of HTTP rules and headers that allow a website to access resources on another website without violating the Same-Origin Policy.
Same-Origin Policy
To fully understand the importance of CORS, it is crucial to understand the politics of the same origin. This is a security measure implemented in browsers to limit interactions between different domains. According to this policy, scripts running on a web page can only access resources from the same domain, protocol and port from which the page was loaded. For example, if a website on http://dominioA.com
try to make an AJAX request to http://dominioB.com
, the request will be blocked unless dominioB.com
does not provide adequate CORS authorizations.
Types of Resources
CORS is applicable to a variety of web resources, including:
- JavaScript file
- CSS style sheets
- Images and videos
- Font
- RESTful API and JSON data
Operation of CORS
When a resource from domain A tries to access a resource on domain B, the browser sends an HTTP request to domain B. This request includes several CORS headers, such as Origin
, which indicates which domain the request comes from. The server on domain B can then respond with its own CORS headers, such as Access-Control-Allow-Origin
, to indicate whether the request is authorized or not.
If the request is authorized, the browser proceeds with the operation. Otherwise, the browser blocks the request and usually reports an error in the development console, telling you that the request was blocked due to the same-origin policy.
CORS Preflight
In some cases, before sending the "real" request, the browser sends a preliminary request called "preflight" using the HTTP method OPTIONS
. This is to check whether the next request is safe to make. The server responds to this preliminary request with the appropriate CORS headers, indicating whether the original request is allowed.
CORS is, in short, an essential mechanism that allows greater interactivity and integration between websites, while maintaining high security standards. Through a set of HTTP headers and well-defined rules, CORS offers a way to securely bypass same-origin policy restrictions, making the web a more flexible and secure environment.
Because it is important ?
In the modern web era, applications are often distributed across multiple domains or services. For example, you might have a front-end application hosted on dominioA.com
which interacts with an API backend on dominioB.com
. In an ideal world, you would like these two parts of the application to be able to freely communicate with each other to provide a smooth and functional user experience. However, the reality is a little more complicated due to a security measure implemented in browsers called the Same-Origin Policy.
The Same Origin Policy was introduced to protect users from potential Cross-Site Request Forgery (CSRF), Cross-Site Scripting (XSS) attacks, and other types of security vulnerabilities that may arise when websites from different origins interact between them. In practice, this policy prevents a web page from making requests to another domain without explicit authorization. So, without a mechanism like CORS, the browser would block any attempts from the front end to dominioA.com
to make requests to the backend on dominioB.com
.
This becomes a significant problem when dealing with modern web applications that require a high degree of interactivity and dynamic functionality. For example, if you have an online store with a shopping cart that needs to check the availability of a product in real time, or a social media application that needs to load posts from an API server, the limitation imposed by the same origin policy could represent an insurmountable obstacle.
That's where CORS comes in. With CORS, you can set specific rules on the backend server that allow the frontend to interact with it despite them being hosted on different domains. This not only improves the functionality and usability of web applications, but does so in a way that maintains high security measures. In other words, CORS offers the best balance between security and functionality, allowing developers to build rich, interactive web applications without compromising end-user security.
CORS at HTTP Header Level
CORS works by adding new HTTP headers that allow servers to describe which sources are allowed to access resources on a web server. Some of the most common CORS headers include:
Access-Control-Allow-Origin
: Specifies which sources can access the resource.Access-Control-Allow-Methods
: Specifies the HTTP methods that can be used when accessing the resource.Access-Control-Allow-Headers
: Specifies headers that can be used when making an HTTP request.
CORS implementation in NGINX
NGINX is one of the most popular web servers and offers high flexibility to configure CORS settings. Here is an example of how you can configure CORS in NGINX:
location /api/ { if ($request_method = 'OPTIONS') { add_header 'Access-Control-Allow-Origin' '*'; add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS'; add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range'; add_header 'Access-Control-Max-Age' 1728000; add_header 'Content-Type' 'text/plain; charset=utf-8'; add_header 'Content-Length' 0; return 204; } if ($request_method = 'POST') { add_header 'Access-Control-Allow-Origin' '*'; add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS'; add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range'; } if ($request_method = 'GET') { add_header 'Access-Control-Allow-Origin' '*'; add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS'; add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range'; } }
In this example, we used the directive location
to specify that CORS rules apply only to requests that point to the resource /api/
. We then used the variable $request_method
to apply different sets of CORS headers depending on the HTTP method used.
Security Considerations
While the use of wildcard *
in the header Access-Control-Allow-Origin
While it is convenient to allow any source to access your resources, it is also a potentially dangerous practice from a security perspective. We recommend that you explicitly specify which sources are allowed.
Conclusion
CORS are a critical building block for security and functionality in modern web development. They allow secure communication between different domains, overcoming the limitations imposed by the same origin policy. Implementing CORS in NGINX is relatively simple but requires a detailed understanding of HTTP headers and potential security implications. We hope this article has provided you with the information you need to effectively and safely implement CORS in your NGINX environment.