The Dangers of Misconfiguring CORS Headers on a Web API Server

Did your web application security assessment come back with a misconfigured Cross-Origin Resource Sharing (CORS) policy?

Cross Origin Resource Sharing (CORS) allow origin any

When browsers execute code from within a page’s source code, they cannot distinguish malicious code from safe code. Modern browsers (Chrome, Edge, Safari, and FireFox) restrict requests to third-party domains by default unless someone modified the policy.

Web developers occasionally have legitimate reasons to allow third-party domains to retrieve data. Using Cross-Origin Resource Sharing (CORS) headers, you can allow these cross-site requests while mitigating the threat of Cross-Site Request Forgery (CSRF) attacks. Please note that your CORS policy is NOT a substitute for anti-csrf tokens, which should be your first line of defense against CSRF attacks. Both are important and should be properly configured.

 

CORS and CSRF Attacks

In a CSRF attack, an attacker crafts a link or web page to perform a request from a remote server in the context of the authenticated user. The user is tricked into clicking a link or pointing a browser to the attacker-controlled web page, and the malicious code performs an action based on the user’s authenticated account permissions.

 

A common CSRF attack uses GET requests using links that contain specific parameters used by the web application to perform an action. For instance, suppose the following GET request triggers your application to return an authenticated user’s name in a JSON object:

 

yoursite.com/userinfo.php

 

This page might use a cookie or session variable to identify that the user requesting information is the legitimate authenticated user. Using the right parameters, your API could perform an action based on the user’s authenticated permissions. For instance, suppose you have parameters that send an email to a given address in the URL’s query string such as the following:

 

yoursite.com/userinfo.php?sendemail=attacker@attackersite.com

 

If the email generated contains sensitive information, an attacker can obtain it by tricking a user into clicking the above link. Even if you detect authentication using cookies or a session, the attack would be successful.

 

This page could also be used as an API resource for your web application where you use it to retrieve data from another domain or from a mobile application. Using the user’s current credentials, the user is not required to authenticate each time the URL is called.

 

An attacker can use the API URL to retrieve user information in the context of the already authenticated user session. For instance, suppose an attacker links a user to the following URL:

 

attackersite.com/hello.html

 

Within this page, the attacker can include JavaScript that makes a call to your site’s API “userinfo.php” page. Calls to external pages in JavaScript are often done using an Ajax object called “XMLHttpRequest” available from the browser. When a call is made from the attacker’s site page, the browser’s CORS policy will reject the request and return an error. A browser’s CORS policy is meant to block attacks including Cross-Site Scripting (XSS) that could be used to retrieve remote data and send it to a third party. A malicious JavaScript call from the attacker’s site could look like the following:

 

var xhr = new XMLHttpRequest();

xhr.open(“GET”, “yoursite.com/userinfo.php”, true);

var response = xhr.responseText;

 

The “response” variable would contain the user’s information and expose it to the attacker. However, with CORS, this request would be blocked provided the API’s server is not misconfigured.

 

Bypassing CORS Restrictions Using Access-Control-Allow-Origin

 

For a single application, CORS can be a helpful security tool but it’s also a hindrance for legitimate applications. Suppose your application runs on “domain-b.com.” You need to retrieve information about a user from the “yoursite.com/userinfo.php” API endpoint. The call is within your website environment, but CORS will block it due to it being on a third-party domain.

 

Developers decided that there was a need to legitimately bypass CORS, so the “Access-Control-Allow-Origin” server header was introduced. This header provides a whitelist of domains allowed to make calls to the local application from an external domain. The user’s browser verifies that the domain making the call is included in the whitelist and allows an application to bypass CORS restrictions.

 

Using the same scenario above, “yoursite.com” would return the “Access-Control-Allow-Origin” server header telling the browser that a third-party call from “domain-b.com” is permitted. The browser would then allow a call to “yoursite.com” from “domain-b.com.”

 

To allow the CORS bypass, you would configure “yoursite.com” with the following header:

 

Access-Control-Allow-Origin: http://yoursite.com

 

Notice that the HTTP protocol is included. In most cases, you would use HTTPS, which should be used instead of HTTP when making requests for sensitive information on the internet. If you want to allow multiple sites to access data from this domain, your code should identify the requesting domain and add it to the “Access-Control-Allow-Origin” programmatically.

 

Creating a Vulnerability with Misconfigured Headers

The Access-Control-Allow-Origin header allows developers and server administrators to set a wildcard. The header looks like the following:

Access-Control-Allow-Origin: *

This configuration tells the browser that any domain can make a call to the resource. The misconfiguration tells browsers to bypass all CORS restrictions and allow any web application to make a call to the resource. This misconfiguration leaves users open to several attacks including XSS and CSRF.

 

Now, consider the previous scenario where an attacker convinces users to click on a phishing link that points to:

 

attackersite.com/hello.html

 

The web page contains a JavaScript script such as the following:

 

var xhr = new XMLHttpRequest();

xhr.open(“GET”, “yoursite.com/userinfo.php”, true);

var response = xhr.responseText;

 

This is a simple example, but APIs that return extremely sensitive information could be vulnerable to this type of attack, leaving users open to identity theft. The attacker can obtain any users’ personal information without restrictions.

 

Using the asterisk in the Access-Control-Allow-Origin header is worse than eliminating the header altogether. The wildcard gives all sites permission to retrieve data. This is one of the most common vulnerabilities on the web because developers are in a rush to meet deadlines.

 

How to Configure Your CORS Policy

The better way to handle this situation is to to simply maintain a whitelist of allowed domains. Remember that the domain URL should include the protocol and HTTPS (TLS) should be used if you’re delivering sensitive information.

The Access-Control-Allow-Origin header is beneficial for developers that have several applications on separate domains, but when it’s misconfigured it can create a dangerous vulnerability. When auditing your application for security concerns, use this header properly to ensure that it does not leave it open to exploits.

For Apache

You can configure Apache using mod_headers. It is enabled by default, however you may want to verify this by running:

 a2enmod headers

Set the following.

 <IfModule mod_headers.c>
   Header set Access-Control-Allow-Origin "INSERT_ALLOWED_ORIGIN_HERE"
 </IfModule>

Then restart Apache.

 

For IIS

Configuration can be accomplished using the IIS CORS Module. More information can be found Here.