New release : CTI Report - Pharmaceutical and drug manufacturing 

                 Download now

HTML5 – CORS: Securing cross-domain application communications

HTML5 – CORS: Securing cross-domain application communications

As part of its research activities, Intrinsec has focused on the features and risks introduced by the arrival of HTML5. This post discusses Cross-Origin Resource Sharing (CORS), the misuse of which could have a significant impact on the application and the company hosting it.

Previously, for security reasons, applications from different domains could not communicate bidirectionally. Domain A could send data to domain B, but could not receive a response. More precisely, B did send a response, but the browser rejected it, detecting that it was not an intra-domain communication.

For more information on these intra-domain communications, refer to the W3C Wikipedia page on the SOP.

The CORS API is implemented in all major browser engines (Gecko 1.9.1, Webkit, Trident 4.0, Presto) and provides various directives via new HTTP headers, including:

  • «"Access-Control-Allow-Origin": this allows you to tell the browser which domains are authorized to receive a response from the server.
  • «"Access-Control-Allow-Credentials": This header indicates whether or not cookies should be transmitted in the response.

Note that, for security reasons, it is not possible to set the headers mentioned above to the following values in the same response:
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true

In practical terms, how are these headers used?

Consider a server "S" whose code is as follows:
<?php
header("Access-Control-Allow-Origin: C");
echo "response";
?>

and let's call it customer "C":
<script>
var http = new XMLHttpRequest();
http.open("GET", "S");
http.onload = function() {
var response = http.responseText;
document.write(response);
}
http.send();
</script>

Here, C does receive the response from S since it is among the authorized "origins".

Examples of misuse of the Access-Control-Allow-Origin header?

Universal authorization

With the configuration below, the page allows any COR sender to receive a response.
header("Access-Control-Allow-Origin: *");
// actions

Let's consider the following scenario: a company has an intranet, accessible only internally, on which the value of the "Access-Control-Allow-Origin" header is set to a wildcard. If an employee connects to a malicious site from the company, they could, for example, make an Ajax request to the intranet and receive data from it, via this configuration.

Conclusion

If the application has restricted access via some authentication mechanism, it is imperative to assign a specific value to this header. Note, however, that if this is not the case, a wildcard can be used. For these public applications (or portions thereof), the W3C recommends, moreover to «open them up» to CORS to allow applications of different natures and authors to communicate with each other.

Access controlled solely by the Origin header

Let's take another example of misuse. The page below displays two different pieces of information depending on the’origin of the request. Access to this page is controlled based on the browser's origin.

if (isset($_SERVER["HTTP_ORIGIN"])) {
if ($_SERVER['HTTP_ORIGIN'] == "http://A") {
header('Access-Control-Allow-Origin: http://A');
echo "Confidential Data".
}
else {
echo "Denied".
}
}

This protection can be bypassed since the Origin header, like any HTTP header, is forgery-able. It should be corrected by only accepting requests that transmit the user's authenticating cookie (with the Credentials Flag, (for Ajax requests, for example). If this cookie is considered valid and if a (valid) token is present, the request can then be processed.

Attack scenario: "silent" CSRF«

Let three protagonists be: a user A having an account on a site B (and therefore a session cookie) and a malicious site O.
This contains the following script:
request = new XMLHttpRequest();
request.open("GET","http://URL_B/service.php?buy=apple",true);
request.withCredentials = "true";
request.onreadystatechange = function() {
if (request.readyState == 4) {
var response = request.responseText;
document.getElementById("response").textContent = response;
}
}
request.send();

Therefore, as soon as the user visits O, a request will be sent to B, via A. The "withCredentials" attribute is set to true This indicates that A's cookie will be transmitted. Therefore, by executing the "buy" action, a CSRF attack occurred without the user initiating it themselves.

One protection from a server perspective against this type of attack is the use of tokens.

As a reminder, a randomly generated token is assigned to a user and stored on the server side, attached to the object representing the user. It is also communicated to the client in cases like the one studied above.
Here, the token would be inserted into the form and, upon validation, the server would verify its authenticity.

Pentesting

How can I check if a website or application is vulnerable to Origin impersonation?
First, it is necessary to know the value of the Origin header expected by the application. The values of this header and the header are often the same.
If the two commands below differ in the content of the downloaded file, then the application is vulnerable:
wget --header="Origin: GoodDomain" URL
wget --header="Origin: BadDomain" URL

What are the key takeaways?
– It is strongly advised against using wildcards when there is access restriction;
– however, if no authentication is required, it is possible to open it via a wildcard;
– do not rely solely on the Origin header: use a system of cookies and tokens;

References

On the safety of the CORS
Silent CSRF