What are CORS attacks

Cross-origin resource sharing (CORS) attacks are made possible through web server misconfigurations. In this article, we’ll look at what CORS attacks are, how they work, and what you can do to avoid them. But before diving into CORS itself, we need to understand a little bit about another important web server security policy: the same-origin policy (SOP).

Same-Origin Policy

Most web servers are configured with a same-origin policy (SOP). What SOP does is restrict the origins from which scripts can access other origins. If that last sentence doesn’t make sense to you, don’t worry – it will. Just bear with me here.

An origin consists of:

  • a URI scheme
  • a domain
  • a port number

It looks like this:

http://regular-website.com/regular-stuff/stuff.hmtl

In the above example, the URI scheme is HTTP, the domain is regular-website.com, and the port is implied to be 80 because our URI scheme is HTTP, which implicitly uses port 80.

An origin is simply a specific location on a web server that may be accessed using a URI scheme, domain, and port number. Both the requesting web server and the requested web server have origins.

With a proper SOP in place, the web server will reject any origin (i.e., another web server’s URI scheme, domain, and port number) requesting access to http://regular-website.com/regular-stuff/stuff using a different URI scheme, domain, or port number.

The same-origin policy is critical because, when a browser makes a request from one origin to another, session cookies could be sent along with the request to generate the response inside the user’s session and provide user-specific and potentially sensitive data. Session cookies are used to keep you logged into a website upon subsequent visits, but could also be used by an attacker to bypass the site’s login process.

Without a proper SOP, were you to log into your banking website, any other open tabs in your browser (if they contained malicious resources) could access your online banking session. If you logged into your email, they could read your emails. If you were having a private chat in a messenger application, they could read your private conversations.

You get the picture.

That’s what SOP is, in a nutshell. It works. But it can be somewhat restrictive. After all, today, there are many websites/online services that interact with each other and require cross-origin access.

That’s where CORS comes in.

What is CORS?

Cross-origin resource sharing (CORS) can be understood as a controlled relaxation of the same-origin policy. CORS provides a controlled way to share cross-origin resources.

The CORS protocol works with specific HTTP headers that specify which web origins are trusted and their associated properties, such as whether authenticated access is permitted. These parameters are expressed in HTTP header exchanges between a browser and the cross-origin website it’s attempting to access.

Here’s what a typical header with the origin parameter specified (bolded) looks like:

GET /resources/public-data/ HTTP/1.1
Host: bar.other User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:71.0) Gecko/20100101 Firefox/71.0 
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip,deflate Connection: keep-alive
Origin: https://foo.example

In the above example, the URI scheme is HTTPS, the domain is foo.example, and the port number is 443 (as implied by HTTPS).

When this header is transmitted to the website, the website will have to make a call on whether or not to allow the cross-origin request. Whether or not the request will be granted depends on the receiving website’s CORS configuration. And it’s this configuration that opens the door to CORS attacks.

If CORS is misconfigured on the web server and ‘foo.example’ is a malicious site, it will accept the request and can fall victim to a CORS attack. But that’s just half the story.

Types of CORS misconfigurations

It’s half the story because there are two main types of CORS misconfigurations that can render a web server vulnerable to CORS attacks – and you need both to pull it off.

  • Access-Control-Allow-Origin (ACAO): This allows for two-way communication with third-party websites. A misconfiguration of the Access-Control-Allow-Origin (ACAO) can be exploited to modify or funnel sensitive data, such as usernames and passwords.
  • Access-Control-Allow-Credentials (ACAC): This allows third-party websites to execute privileged actions that only the genuine authenticated user should be able to perform. Examples would be changing your password or your contact information.

Both of these parameters work in tandem within the web server’s CORS configuration.

They boil down to two questions the web server must answer:

  • Does the web server accept the request from the stated origin?
  • If so, does it also provide credentials for privileged actions to be executed?

The first question corresponds to the Access-Control-Allow-Origin policy, and the second question corresponds to the Access-Control-Allow-Credentials policy.

Let’s look at the different ways web servers can configure their Access-Control-Allow-Origin policy:

Access-Control-Allow-Origin policy

Allow all origins (*)

This allows access from all origins. As soon as a cross-origin request is received, it will be allowed. The response header would look like this:

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

This is referred to as origin reflection because the web server simply “reflects” the origin found in the request header into the response header. The web server is using a wildcard (*) to accept all cross-origin requests.

Note that this isn’t necessarily disastrous from a security perspective. This configuration is used by many public websites or API endpoints that are meant to be publicly accessible.

Allow subdomains (*.website.com)

Setting the ACAO policy to allow subdomains will allow cross-origin requests from any subdomains of the defined domain. If a valid request comes through, it will be allowed. The response header would look like this:

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

Pre/post domain wildcard (*website.com / website.com.*)

Setting your ACAO policy to accept pre or post wildcard requests from a given domain would accept cross-origin requests from evilwebsite.com or website.com.evilsite.com. The response headers would look something like this:

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

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

Null allowed (null)

Many development languages represent non-existent headers with the “null” value. Setting your ACAO policy to null means that the web server will accept cross-origin requests from the “null” origin. This is often deployed in internal web development environments (intranet). The response header would look like this:

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

Now let’s take a look at the Access-Control-Allow-Credentials policy.

Access-Control-Allow-Credentials policy

The Access-Control-Allow-Credentials policy is set with a value of true or false. And it’s really this setting that, when set to “true,” enables most CORS attacks. The response header would look like this:

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

Without this header, the victim’s browser will not send its cookies, so the attacker can only access unauthenticated content, which they could just as easily access by simply browsing the target website.

The severity of the breach opened by the Access-Control-Allow-Credentials policy depends on the Access-Control-Allow-Origin policy. An ACAO policy set to * (Allow all origins) with an ACAC policy set to “true” opens a bigger breach than an ACAO policy set to “Allow subdomains” with an ACAC policy set to “true.”

CORS attack example

Here’s what a CORS attack could look like:

  1. The victim visits evilwebsite.com while being authenticated to goodwebsite.com.
  2. evilwebsite.com dumps a malicious script designed to interact with goodwebsite.com, on the victim’s machine.
  3. The victim unwittingly executes the malicious script, and the script issues a cross-origin request to goodwebsite.com. In this example, let’s assume the request is crafted to obtain the credentials necessary to perform a privileged action, such as revealing the user’s password.
  4. goodwebsite.com receives the victim’s cross-origin request and the CORS header.
  5. The web server will check the CORS header to determine whether or not to send the data to goodwebsite.com. In this example, we’re assuming that CORS is allowed with authentication (Access-Control-Allow-Credentials: true).
  6. The request is validated, and the data is sent from the victim’s browser to evilwebsite.com.

This is a worst-case scenario, where everything is wide open. But it still exemplifies what a CORS attack looks like. And this worst-case scenario is actually quite common. In fact, in 2016, Facebook was found to be vulnerable to such a CORS attack.

The state of the Web

An unofficial study conducted in June 2020 found that from the Alexa top 1 Million websites, only 3% (29,514) of websites supported CORS on their main page.

CORS - Study 1
Source: https://luizmartins.blogspot.com/2020/06/cors-misconfigurations-on-large-scale.html

As we mentioned above, in order to be able to pull off a CORS attack, the Access-Control-Allow-Credentials policy must be set to “true.” Looking at sites that support both the ACAO and the ACAC, the same study found that close to half of them had CORS misconfigurations that a malevolent actor could exploit.

CORS - Study 2
Source: https://luizmartins.blogspot.com/2020/06/cors-misconfigurations-on-large-scale.html

How to prevent CORS-based attacks

It’s primarily web server misconfigurations that enable CORS vulnerabilities. The solution is to prevent the vulnerabilities from arising in the first place by properly configuring your web server’s CORS policies. Here are a few simple tips on preventing CORS attacks.

1. Specify the allowed origins

If a web resource contains sensitive information, the allowed origin(s) should be specified in full in the Access-Control-Allow-Origin header (i.e., no wildcards).

2. Only allow trusted sites

While this one may seem obvious, especially given the previous tip, but origins specified in the Access-Control-Allow-Origin header should exclusively be trusted sites. What I mean to convey that you should avoid dynamically reflecting origins from cross-domain request headers without validation unless the website is a public site that doesn’t require any kind of authentication for access, such as an API endpoint.

3. Don’t whitelist “null”

You should avoid using the header Access-Control-Allow-Origin: null. While cross-domain resource calls from internal documents and sandboxed requests can specify the “null” origin, you should treat internal cross-origin requests in the same way as external cross-origin requests. You should properly define your CORS headers.

4. Implement proper server-side security policies

Don’t think that properly configuring your CORS headers is enough to secure your web server. It’s one of the pieces, but it isn’t comprehensive. CORS defines browser behaviors and is never a replacement for server-side protection of sensitive data. You should continue protecting sensitive data, such as authentication and session management, in addition to properly configured CORS.

As a user, you basically want to be one step ahead of phishing scams and malicious websites and downloads to minimize your chances of falling victim to a CORS attack. The following common-sense tips can help.

These steps are similar for many online attacks such as avoiding fake antivirus so they are generally good practices to follow.

  • Use a firewall – All major operating systems have a built-in incoming firewall, and all commercial routers on the market have a built-in NAT firewall. Make sure you enable these as they may protect you in the event that you click a malicious link.
  • Only buy well-reviewed and genuine antivirus software from legitimate vendors and configure it to run frequent scans at regular intervals.
  • Never click on pop-ups. You never know where they’ll take you next.
  • If your browser displays a warning about a website you are trying to access, you should pay attention and get the information you need elsewhere.
  • Don’t open attachments in emails unless you know exactly who sent the attachment and what it is.
  • Don’t click links (URLs) in emails unless you know exactly who sent the URL and where it links to. And even then, inspect the link carefully. Is it an HTTP or an HTTPS link? Most legitimate sites use HTTPS today. Does the link contain spelling errors (faceboook instead of facebook)? If you can get to the destination without using the link, do that instead.

Stay safe.