Cross-Origin Resource Sharing (CORS) is a method developers use to legitimately bypass Same Origin Policy(SOP). SOP is a security mechanism that prevents scripts from reading the response of a request if its located on a different domain. If a script makes a request to an API endpoint located on a separate domain the SOP will prevent the response from being read. Sometimes developers need to bypass this restriction which is where CORS comes in.
Websites that utilize CORS will send a specially crafted response header that allows a specific domain to bypass the SOP on that application. The Access-Control-Allow-Origin header specifies a domain that is allowed to bypass SOP. In the below example the server responded with example.com. Any requests coming from the example.com domain will be able to bypass SOP.
Access-Control-Allow-Origin: example.com
Using the Access-Control-Allow-Origin header alone will not send user credentials or cookies.CORS however does allow the server to specify if cookies should be sent with the request or not. This is useful if the user is already logged in and you want to grab specific information that requires authentication. This can be accomplished by sending a special response header as shown below.
Access-Control-Allow-Credentials: true
Currently the XMLHttpRequest and the Fetch API follow the same-origin policy. If you make a request to another domain using XMLHttpRequest and Fetch API the response will be dropped because it violates SOP. If CORS is enabled than those calls will be able to bypass SOP.
If CORS is implemented properly there are no security concerns but if it is misconfigured it can make your whole site insecure. There are a few deadly misconfiguration that can leave a website susceptible to attackers. These misconfigurations include:
Origin reflection occurs when the origin is echoed back in the Access-Control-Allow-Origin header. This action is especially dangerous because it allows any domain to bypass the SOP on the vulnerable domain. To test for this misconfiguration you can insert an Origin header in your request and set its value to example.com. If the server responds with an Access-Control-Allow-Origin header set to example.com then we know the website is vulnerable because the origin header value was reflected back.
Loading the below HTML source code on a domain that you control will also allow you to test for this misconfiguration. If you receive the response after submitting the form then the target website is vulnerable to this misconfiguration.
<input id="host" size="30" type="text" value="https://siteHere" />
<input id="path" size="30" type="text" value="/PathHere" />
<button onclick="cors()">Submit</button>
<textarea id="corsleak" readonly="" rows="30" style="width: 99%;"></textarea>
<script>
function cors() {
document.getElementById('corsleak').value = "";
var req = new XMLHttpRequest();
req.onload = listener;
req.open('GET', document.getElementById('host').value + document.getElementById('path').value);
req.withCredentials = true;
req.send();
function listener() {
document.getElementById('corsleak').value = this.responseText;
}
}
</script>
If the target website has the Access-Control-Allow-Credentials: true header set then the website will also accept users cookies and this will allow you to read information from logged in users.
Developers will sometimes check to see if a specific domain is present in the origin header before echoing it back in the Access-Control-Allow-Origin header. At first you might think that validating if the domain example.com exist in the origin is a good idea to limit which origins are reflected back in the response header. To bypass this an attacker can register the domain notexample.com which would pass validation because it contains the words example.com.
Post domain wildcard is similar to the pre domain wildcard misconfiguration. This occurs when developers check the beginning of a domain without verifying the rest. So if a website is checking for example.com in the beginning of the origin header an attacker can set their origin to example.com.attacker.com which would pass the validation check.
Some websites will reflect the origin back if it’s set to null. This may seem harmless because its impossible to register a domain named null thus you could never realistically have your origin header set to null. This would be true except a null origin will be sent in sandboxed iframes. This makes it possible for any domain to bypass the SOP on the vulnerable site.
Many websites will reflect the origin header value if its a subdomain (subdomain.example.com). If an attacker is able to execute code on a subdomain then they will be able to bypass the SOP. This can be accomplished by chaining exploits. An attacker who finds XSS in a subdomain will be able to execute code while having their origin set as that subdomain. An attacker could also perform subdomain hijacking to execute code on a subdomain. Both of these attacks can be used to bypass the subdomain wildcard check since the malicious code is executed on a subdomain.
This isn't the first time attackers have found ways to bypass SOP. Before CORS there was JSONP which was a failed attempt and easily exploited. Flash uses a file called crossdomain.xml and silverlight uses ClientAccessPolicy.xml to bypass SOP. All of these are used to legitimately bypass SOP and if misconfigured they can be exploited by malicious actors.
The Same Origin Policy(SOP) prevents scripts from reading the response of another domain. Sometimes developers try to get around this security policy and if done improperly it can have severe consequences. If a malicious site is able to read another domains authenticated response an attacker could read sensitive information such as a users name, address, credit card, CSRF tokens, or anything else. By adding a simple response header you can leave your whole site vulnerable to malicious hackers.