The Cross-Origin Resource Sharing (CORS) is a mechanism to relax the Same Origin Policy (SOP) and to enable communication between websites, served on different domains, via browsers.

Inside this blog, the reader will find:

  • A brief introduction to the Same Origin Policy (SOP) and Cross-Origin Resource Sharing (CORS)
  • Main techniques to attack an application with CORS enabled
  • General guidelines to implement CORS securely

Cross-Origin Resource Sharing (CORS)

Same Origin Policy (SOP)

The same-origin policy is a web browser security method that aims to prevent websites from attacking each other. The same-origin policy limits scripts on one origin from accessing data from another origin.

The term “origin” is defined using: Domain name, Application protocol, and TCP port.

Two resources are considered to have the same origin if and only if all the preceding three values are the same.

To better explain the concept, the following table shows the results of the control of the Same Origin Policy with respect to the URL http://www.example.com/dir/page.html

 

SOP Scenario

Fig-1.1 SOP Scenario

 

Cross-Origin Resource Sharing (CORS)

There are several techniques available for relaxing the SOP in a controlled manner. One of these techniques is Cross-Origin Resource Sharing. Through the configuration of additional HTTP headers, it tells the browser that a request generated by a web application running at origin “A”, has the permission to access the selected resource served on origin “B”.

The main header involved is the “Access-Control-Allow-Origin”. This header allows the listed origin to make visitor’s web browsers send cross-domain requests to the server and read the response. Something the Same Origin Policy would normally prevent. For example, Access-Control-Allow-Origin: https://example.info

By default, without the “Access-Control-Allow-Credentials” header, a request will be issued without credentials (like cookies or HTTP Authentication data), meaning that it cannot be used to steal private user specific information. And if it is set to “true” by the server then it allows the browser to send authenticated requests to the target handler.

The following image shows a simple CORS request flow:

 

Simple CORS flow

Fig-1.2 Simple CORS flow

 

  1. Exploiting with Credentials:

From an attacker’s point of view, the best scenario is when the target CORS configuration sets the “Access-Control-Allow-Credentials” header to “true”. In this case, the attacker can exploit the misconfiguration identified to steal the victim’s private and sensitive data. And the basic technique is to create a JavaScript that sends a CORS request.

For example:

JavaScript for exploiting with credentials

Fig-2.1 JavaScript for exploiting with credentials

With this code, the attacker can steal the data through the “log” handler that receives the response from the vulnerable domain. When the victim authenticated on the target application (“vulnerable.domain”) visits the page containing the earlier code, the browser sends the following request to the “vulnerable.domain”:

Tampered domain or attacker domain

Fig-2.2 Tampered domain/attacker domain

And the application responds with the following:

Server response

Fig-2.3 Server response

Due to the two “Access-Control-Allow-*” headers sent by the server; the victim’s browser allows the JavaScript code included into the malicious page to access the private data.

Misconfigured CORS result

Fig-2.4 Misconfigured CORS result

 

  1. Using special characters

There is a possibility to bypass some controls implemented incorrectly using special characters inside the domain name.

This evasion technique exploits the fact that browsers do not always validate domain names before making requests. Therefore, if some special characters are used, the browser may submit requests without previously verifying if the domain name is valid.

Suppose the target application implements the following regular expression to validate the “Origin” header:

Simple regular expression example

Fig-3.1 Simple regular expression example

The meaning of the above regular expression is likely to allow cross-domain access from all subdomains of “target.local” and from any ports on those subdomains.

“[^\.\-a-zA-Z0-9]” means any character except the “.” “-” “a-z” “A-Z” “0-9”

“+” means a quantifier, matches preceding chars one or more times.

“.*” means any character except for line terminators.

Captured request

Fig-3.2 Captured request 

In this screenshot, no “Access-Control-Allow-Origin” & “Access-Control-Allow-Credentials” are set.

Since the regex matches against alphanumeric ASCII characters and “.” “-“, every other special character after “target.local” would be trusted.

Tamper the origin https://www.taget.local.example.com with https://www.taget.local{.example.com

Origin tampered

Fig-3.3 Origin tampered

The prerequisites to exploit this are: A domain with a wildcard DNS record pointing it to your server and NodeJS

Create a serve.js file:

Serve.js contents

Fig-3.3 Serve.js contents

Then in the same directory create the cors.html:

Cors.html file

Fig-3.4 Cors.html file

Now start the NodeJS server by running the command: node serve.js &

Due to the regular expression ^https?:\/\/(.*\.)?target.local([^\.\-a-zA-Z0-9]+.*)? which is implemented on the target application, every special character, except “.” and “-“, after “www.target.local” would be trusted, so the request generates a valid request and the attacker is able to steal data from the vulnerable target.

 

  1. Client-side cache poisoning:

For example, consider an application that reflects inside the response the content of the “X-User” custom header, without doing any input validation on it nor doing output encoding.

Request:

Captured request

Fig-4.1 Captured request

In response, note that the “Access-Control-Allow-Origin” is set but the “Access-Control-Allow-Credentials: true” and “Vary: Origin” headers are not set as shown below:

Server response

Fig-4.2 Server response

An attacker can exploit this XSS by uploading the following JavaScript code on a controlled server and then making a victim to navigate on it:

JavaScript code

Fig-4.3 JavaScript code

If the “Vary: Origin” header is not set inside the response, then the victim’s browser may store the response in the cache and then displays it directly when the browser navigates to the associated URL which is shown below:

Misconfigured CORS result

Fig-4.4 Misconfigured CORS result

 

Cross-Origin Resource Sharing (CORS) mitigation techniques:

  1. It is necessary to evaluate if it is necessary to enable CORS. If it is not strictly necessary, it is advisable to avoid it at all to not weaken the SOP.
  2. If possible, prefer a whitelist compared to regex implementations because regex is more prone to error that could lead to CORS misconfigurations.
  3. Never configure the “Access-Control-Allow-Origin” header to the value of wildcard (*).
  4. When a cross-domain request is received, it is necessary to check whether the “Origin” header received matches exactly one of the allowed sources.
  5. It is necessary to validate the protocol to ensure that no interaction from an insecure channel (HTTP) are allowed otherwise an active man-in-the-middle (MITM) attack could bypass the use of HTTPS on the application.
  6. It is also necessary to return the “Vary: Origin” header to avoid potential attacks that exploit the browser cache.
  7. It is also advisable to limit the period for which the browser can cache information provided through the “Access-Control-Allow-Methods” and “Access-Control-Allow-Headers” headers. This can be done by using the “Access-Control-Max-Age” header, which receives as input the number of seconds for which the “preflight request” can be kept in a cache. Configuring a relatively low value (for example around 30 minutes) ensures that any updates to policies (e.g., allowed sources) are considered by browsers in a short time.
  8. Avoid using the header Access-Control-Allow-Origin: null. Cross-domain resource calls from internal documents and sandboxed requests can specify the null origin. CORS headers should be properly defined in respect of trusted origins for private and public servers.

 

References:

 

Author,

Avadhoot Dongare

Attack & PenTest Team

Varutra Consulting Pvt. Ltd.