OWASP TOP 10: Security Misconfiguration #5 – CORS Vulnerability and Patch

What is the meaning of an origin?

Two websites are said to have same origin if both have following in common:

  • Scheme (http, https)
  • Host name (google.com, facebook.com, securelayer7.net)
  • Port number (80, 4567, 7777)

So, sites http://example.com and http://example.com/settings have same origin. But https://example.com:4657 and http://example.com:8080/settings have different origins.

The ‘Same Origin Policy’ restricts how a script loaded from one origin can interact with a resource from another origin. It is an important built-in security mechanism for browsers for isolating potential malicious scripts.

What is cross origin resource sharing?

It is the need of Web 2.0 to share resources across origins. Following are some examples:

  • Cross Origin Writes: A website can POST data to an endpoint of another website.
  • Cross Origin Embedding: A website can refer images from another website using <img src> tag. Also, an iframe using <iframe src> tag can be embedded if the source website allows it.

Apart from the above two scenarios, when one website reads data from another website, it is called as ‘Cross Origin Resource Sharing’ aka CORS.

CORS is a W3 specification that allows cross domain communications from the browser. It works by adding new HTTP Headers that describe the origins that are allowed cross domain information sharing.

In other words, CORS is used to relax the ‘Same Origin Policy’ for legitimate and trusted requests. It is an essential feature of Web 2.0 to support APIs that are exposed via web services to be accessible.

Some noteworthy example of web applications supporting CORS: Google, Youtube, Flickr.

Two most important CORS Headers:

  • Origin: It is set by browser in every CORS request. Its value is the domain name from which the request originates.
  • Access-Control-Allow-Origin: It is set by server in every CORS response. Depending on its value, the browser decides if the response is allowed or not. It can be set to * (also called the wildcard character) to make resources public (However, this is not a good practice).

A scenario to exploit CORS vulnerability:

In this demo we are going to use a vulnerable intranet application which has a secret located at ‘secret-cors-3.php’.  It has an Admin who accesses it from his local environment. Its URL is: http://127.0.0.1:80/bwapp/.

As it is an intranet application, the attacker cannot interact with it remotely. Our goal as an attacker will be to capture the secret (from a remote internet location) by exploiting CORS vulnerability.

The exploitation:

1. The attacker hosts a website containing the malicious script for cross domain interaction.

2. Victim i.e. the Admin of the intranet website visits the attacker’s website. Location http://127.0.0.1:4567

 CORS Vulnerability

3. Response is received from the attacker’s website containing the following malicious payload:

CORS Vulnerability

4. As soon as the web page is loaded, ‘makeRequest’ method is called. The method initiates a cross domain request to capture the secret, to the vulnerable intranet application located at ‘http://127.0.0.1:80/bwapp/secret-cors-1.php’

CORS Misconfiguration

 

5. It fetches the response and stores it in the variable ‘secret’.

Cors

6. The ‘Access-Control-Allow-Origin’ has value set to *. So, the malicious script now has the payload and it simply issues a GET request to the attacker’s web server. Attacker hosts another web server at location: http://127.0.0.1:7777

Attackers CORS

7. Meanwhile, attacker monitors the logs of that web server. The payload gets executed and the logs receive the secret.

CORS

How to mitigate it?

    • ‘Access-Control-Allow-Origin’ should be never set to * if the resource contains sensitive information.
    • The mitigation is simple and just a proper configuration. Configure the Access-Control-Allow-Origin header to allow requests only from the domains that you trust. For e.g.: Access-Control-Allow-Origin: saurabh.com The below image illustrates that the CORS attack does NOT get executed when the server is configured with correct ‘Access-Control-Allow-Origin’ instead of a ‘Wildcard’ character.CORS Patch

 

  • Make sure that in server side validation for checking the origin header value, you are comparing with absolute value and NOT with regular expression.
  • For example: The following code does a comparison with regular expression:
                RegEx(“^https://mail.example.com$”)
    In the above validation, dots (.) mean any character. So, an attacker can bypass it by making the CORS request origin from following domain:
    https://mailxexample.com
    The patched code will be:

                if($_SERVER[“HTTP_ORIGIN”] == “https://mail.example.com”)
                       {
                           header(“Access-Control-Allow-Origin: https://mail.example.com”);
                       }
  • Client should not trust the received content without sanitization because that will result in client side code execution. For example: If website abc.com trusts and fetches cross domain data from example.com. example.com has a malicious intent and starts sering malicious javascript to abc.com, then abc.com can protect its users from cross site scripting by sanitizing the received data and then presenting it to its users.

What if the Origin header is spoofed?

The point of origin header is not to protect the resources on the server, that task is up to server itself. Origin header is to protect the user. Following scenario demonstrates it:

  • An attacker Charlie creates a malicious website M
  • User Alice is tricked into visiting website M which tries to perform CORS action on server example.com that supports it.
  • The domain example.com will be listed in website M’s list of allowed domains. So, the request will be rejected.
  • The important point here is that M cannot spoof the origin header because the request is initiated from Alice’s browser.
  • This can be done by Alice using a local proxy tool. But why would a victim hack himself, so this scenario is not real.

Another way, an attacker can do this, is by intercepting the request being a man in the middle. But if the attacker has access to the traffic, then capturing cookies and session ID are better options rather than changing the Origin header.

OWASP category for CORS Vulnerability:

This vulnerability falls under to the category of ‘Security Misconfiguration’ of OWASP Top 10. The HTTP response header ‘Access-Control-Allow-Origin’ is not configured correctly and this creates the issue.

References:

 

 

  • For example: The following code does a comparison with regular expression:
    RegEx(“^https://mail.example.com$”)
    In the above validation, dots (.) mean any character. So, an attacker can bypass it by making the CORS request origin from following domain: https://mail.exampleccom.com

    Surely that domain doesn’t match that regex? Whilst a dot is a wildcard, in every flavour I’ve used, it matches a single character, so it will not match com., which would be required given the $ anchor at the end. A better example is presumably https://mailxexample.com.

    • SaurabhB

      @Peter, You are correct. I have updated it. Thanks for letting us know that 🙂