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)
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.
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. 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, attacker monitors the logs of that web server. The payload gets executed and the logs receive the secret.
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.
- 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:
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”)
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.
- 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