To avoid exposure to a variety of web application vulnerabilities, specific security considerations must be made when implementing Cross-Origin Resource Sharing
Today’s modern web applications rely heavily on JavaScript to be dynamic, and ensure the best experience for end-users. Providing content and data to the users often requires interactions with other web applications, which include cross-domain requests and an additional configuration step on the application side known as a Cross-Origin Resource Sharing (CORS) policy.
In this post, we will explain how a misconfiguration of a CORS policy can make your web application vulnerable, and how the Tenable.io Web Application Scanner (WAS) can help you identify these vulnerabilities.
CORS “Origins”
The web application security model implemented by web browsers is built using multiple concepts, with one of the most important being the Same-Origin Policy (SOP). The purpose of the SOP is to restrict interactions between scripts loaded on the origin and the resources hosted on other origins. An origin consists of a combination of the protocol, hostname, and port.
CORS is an extension to the SOP defined by the World Wide Web Consortium (W3C), which enables web applications to add the origins allowed to read responses to cross-domain requests to an allowlist and enforce it at the client browser level.
The implementation of the CORS standard relies on the introduction of multiple Hypertext Transfer Protocol (HTTP) headers used in the communication between the client and the target application.
In the simplest example of implementing CORS, when a web browser loads a web page requesting cross-domain resources, the Origin HTTP header is added in the request to the external resource. The application’s response will then include the Access-Control-Allow-Origin header to define which origins are authorized to read the application responses. In certain instances, the Access-Control-Allow-Credentials header may also be part of the responseto specify whether or not the calling script is allowed to ask the browser to include credentials in the cross-domain request, such as session cookies, authorization headers, or TLS client certificates. Upon receiving the cross-domain target application’s response, the client browser checks if the origin is granted to read the response or blocks it according to the configured CORS policy.
Complex requests like the ones using specific HTTP methods, such as PUT or DELETE, or custom HTTP headers will trigger an additional request called apreflight request. The preflight request is first issued with an OPTIONSrequest, which is designed to check if the target application has CORS enabled and supports the different options sent in the request.
In this situation, the application response contains additional headers like the Access-Control-Allow-Methods HTTP header, which specifies the HTTP methods allowed when using cross-domains requests.
Once the preflight request is complete, the real request is sent to the target application.
Common vulnerabilities
Because CORS is an access control mechanism, it can be misconfigured, thereby enabling an attacker to bypass it and make the client browser act as a proxy between a malicious website and the target web application. Most of the time the related security risk is underestimated and becomes more important when the web application allows authenticated requests.
One of the most common misconfigurations is the value defined in the Access-Control-Allow-Origin header sent back by the application. The list below describes some of the most common errors made when defining a CORS policy
- When using a wildcard with a value of an asterisk (*) in the Access-Control-Allow-Origin header, any origin is allowed to read responses from cross-domains requests. The CORS specification includes a particular security check for this scenario that prevents the Access-Control-Allow-Credentials header to be set to “true” in this case.
- Using a “null” value and assuming this will disable cross-domain request capabilities. On the contrary, this configuration has the same impact as using a wildcard. Web browsers automatically use the null origin in some circumstances, such as after a CORS request has been redirected by the target resource, or when this request has been sent from a specific resource type (for example, from an iframe, or using a local file).
- Building dynamic Access-Control-Allow-Origin with improper server-side validation. The specification only defines a single origin in the Access-Control-Allow-Origin response header. When multiple origins need to be trusted, developers have to deal with dynamic validation of the origin by using regular expressions based on the target application domain.
In the case of misconfiguration, the regular expression can, for example, implicitly authorize the application derived hostname. In other situations, the Origin header sent by the web browser is simply reflected, leading to the same impact as using a wildcard value. This is a common practice to circumvent the control that prevents using both the wildcard allowlist and the credentials.
- “Trusting” public third party services. Hosting infrastructures like Cloud providers (storage buckets), content delivery networks (CDNs), or code hosting services are sometimes allowed in the CORS policy. By definition, these public services are available for a potential attacker who can leverage them to host malicious JavaScript code and issue cross-domain requests to the vulnerable application.
Exploitation and security risks
With some background on the different vulnerabilities associated with CORS misconfigurations, let’s have a look at the security risks and impacts.
The common exploitation scenarios can be described by the following steps:
- An attacker sets up a malicious website hosting JavaScript code, which aims to retrieve data from a vulnerable web application.
- The attacker entices the victim to visit the website using phishing or an unvalidated redirection in the target application.
- The JavaScript code is then loaded in the victim browser and performs silent cross-domain authenticated requests to the target application to steal data and store it.
Although the risk increases when the CORS policy allows the usage of requests with credentials, there can be situations where a simple origin that is not properly validated can have a big impact. For example, intranet web applications sometimes do not follow a standard security design and may allow any user located on the corporate network to reach its internal content without authentication. If the application's CORS policy is not correctly enforced and the victim user visits the malicious website, this could result in an information leak.
Information leakage is a basic exploitation case of CORS vulnerabilities. However, attackers often leverage these issues to perform advanced attack scenarios, which can lead to the takeover of application user accounts or the execution of arbitrary modifications in the target application on behalf of the victim user. Earlier this year, Chris Lyne, senior research engineer on Tenable’s Zero Day Research Team, disclosed a vulnerability in Plex Media Server due to a weak CORS policy and described the related risks for the Plex application users.
Leverage Tenable.io WAS to detect CORS issues
Tenable.io WAS helps you identify CORS issues with multiple plugins designed to audit a web application during a scan. The main purpose is to be able to:
- Check that the Access-Control-Allow-Origin is not too permissive according to the best practices.
- Verify that the origin validation is properly enforced by using the most common bypasses known by Tenable Research.
Once detection of a CORS issue occurs, Tenable.io WAS provides the relevant information helping identify the configuration to fix, as well as the related guidance to remediate the issue.
Generally speaking, CORS vulnerabilities are configuration errors and can be easily fixed with the following principles:
- If the application does not require cross-origin requests, the only action is to check that no policy is set.
- Always ensure that the Access-Control-Allow-Origin header allows the most specific origins and is not over permissive. A wildcard configuration should only be defined when the whole content of the application is made to be public.
- Restrict the Access-Control-Allow-Methods header to match what the application needs.
- Consider using real “trusted” origins. By default, public Cloud providers or services like GitHub Pages should not be in your trust zone when dealing with CORS.
- Set the Access-Control-Allow-Credentials header to true only when required and after having validated that the Access-Control-Allow-Origin header is properly set.
Finally, it is important to note that a CORS policy is not a security feature by itself and still requires common application security best practices.
Get more information
- Tenable.io Web App Scanning
- Mozilla Developer Network - Cross-Origin Resource Sharing
- OWASP HTML5 Security Cheat Sheet - Cross-Origin Resource Sharing
- Plex Media Server Weak CORS Policy (TRA-2020-35)
- Insecure 'Access-Control-Allow-Origin' Header (Plugin ID 98057)
- Insecure Cross-Origin Resource Sharing Configuration (Plugin ID 98983)