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 CORS (Cross Origin Resource Sharing)?
CORS is a browser mechanism that extends the same-origin policy (SOP), which restricts how a script from one origin can interact with resources from another. It allows servers to specify which origins can access their resources, facilitating secure cross-origin interactions in Web 2.0.
Examples of cross-origin scenarios include:
- Cross-Origin Writes: Websites can POST data to endpoints on other domains.
- Cross-Origin Embedding: A website can refer to 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 Cross Origin Resource Sharing (CORS).
CORS operates through HTTP headers that define permitted origins, enhancing security while enabling access to shared resources. It relaxes the ‘Same Origin Policy’ for legitimate and trusted requests, making it an essential feature of Web 2.0 to support APIs exposed via web services.
Notable examples of web applications that support CORS include Google, YouTube, and Flickr.
Two most important CORS Headers:
- Origin: It is set by the browser in every CORS request. Its value is the domain name from which the request originates.
- Access-Control-Allow-Origin: It is set by the 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 the 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
3. A response is received from the attacker’s website containing the following malicious payload:
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’
5. It fetches the response and stores it in the variable ‘secret’.
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
7. Meanwhile, the attacker monitors the logs of that web server. The payload gets executed, and the logs receive the secret.
How to mitigate CORS Vulnerability?
Access-Control-Allow-Origin’ should never be 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 example: Access-Control-Allow-Origin: saurabh.com
The below image illustrates that the CORS attack does NOT get executed when the server is configured with the 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 the 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”);
}
Clients should not trust received content without sanitization, as this can lead to client-side code execution. For example, if the website abc.com trusts and fetches cross-domain data from example.com, and example.com has malicious intent and serves malicious JavaScript to abc.com, abc.com can protect its users from cross-site scripting by sanitizing the received data before presenting it to users.
What if the Origin header is spoofed?
- An attacker (Charlie) creates a malicious website (M).
- A user (Alice) is tricked into visiting website M, which attempts a CORS action on server example.com.
- The domain example.com will be in M’s list of allowed domains, so the request will be rejected because M cannot spoof the origin header (the request is initiated from Alice’s browser).
- Although Alice can use a local proxy tool to spoof the origin header, this scenario is unlikely as it involves the victim hacking themselves.
- An attacker could also intercept the request as a man-in-the-middle, but if they have access to the traffic, capturing cookies and session IDs are better options than changing the origin header.
By implementing these strategies, the risk of CORS vulnerabilities can be significantly mitigated, enhancing overall web application security.
OWASP CORS Vulnerability:
This vulnerability falls under the category of ‘Security Misconfiguration’ in the OWASP Top 10. The HTTP response header ‘Access-Control-Allow-Origin’ is not configured correctly and this creates the issue.
References:
- In the demo, Bwapp was used as the target web application. It is a deliberately made insecure web application. More about it at – http://www.itsecgames.com/
- CORS Introduction – https://en.wikipedia.org/wiki/Cross-origin_resource_sharing
- Same Origin and Cross Origin Policies: https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy