XSSI designates a kind of vulnerability that exploits the fact that, when a resource is included using the script tag, the SOP doesn’t apply, because scripts have to be able to be included cross-domain. An attacker can thus read everything that was included using the script tag. This is especially interesting when it comes to dynamic JavaScript or JSONP when so-called ambient-authority information like cookies are used for authentication. The cookies are included when requesting a resource from a different host.


WHAT IS THE SAME-ORIGIN POLICY?

The Same-origin policy or more simply SOP is one of the most important protections of the Internet browser. It is used to verify that the content loaded on the page comes from the same domain. The Firefox documentation gives us a table that shows how this security protocol work. Two URLs have the same origin if the protocol, port (if specified), and host are the same for both. You may see this referenced as the "scheme/host/port tuple", or just "tuple".

image-1

To make it simple, the SOP prevents an attacker from being able to retrieve information from another site with the rights of a logged-in user. Consider the following example which shows an attack diagram with the SOP disabled on the user side:

image-2

It can be seen here that without the SOP any site visited can access another site using the user's cookies. When the SOP is activated, an error will appear.


THE LIMITS OF THE SOP

We quickly saw how the SOP works, but there are also some limitations to this protection. Indeed, the SOP must be permissive enough to be able to display images or load external JavaScript. The following examples are therefore not subject to this protection:

The image tag

<img src="http://externe.dtd/image.png" />

The script tag

<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>

Other examples of tags such as link or video are available in the Firefox documentation. This permissive mechanism allows considering a scenario in which the SOP does not work.


THE XSSI

So what is an XSSI? An XSSI, also called Cross-Site Script Inclusion, is the inclusion of a remote page with content in JavaScript. Indeed, the script tag includes, via its src attribute, an external page that is loaded as being JavaScript.

Take the example of the following PHP code:

var info = [{'user' : 'NeosLab', 'API_KEY' : 'l3x11sG00dBuT3l54J34n1sB3tt3r'}];

In the following code, we assume that the get_user_info() function retrieves information from a database using the user cookie.

<?php
session_start();
function get_user_info()
{
$info = "{'user' : 'NeosLab', 'API_KEY' : 'l3x11sG00dBuT3l54J34n1sB3tt3r'}";
return $info;
}
header('Content-Type: application/javascript');
$build_response = "var info = [". get_user_info() ."];";
echo $build_response;
?>

We notice that the PHP script changes the Content-type of the page. We can assume that for practical reasons the information is loaded dynamically on the site via Javascript. However, this type of use is not secure at all as shown in the following script.

<script src="https://www.neoslab.com/labs/info.php"></script>
<script type='text/javascript'>
alert(JSON.stringify(info));
</script>

image-3

An attacker can therefore set up the following:

image-4

There are ways to load other types of files (CSV, JSON) by playing with the charset of HTML elements as shown in this document. However, most of the workarounds presented no longer work on recent versions of browsers.


ORACLE XSS

Let's say that a page of a site returns different HTTP codes (200, 404, 302, etc ...) in response to different GET-type requests. It would then be possible to retrieve these codes using the error handler. Indeed, by playing with these handlers, it is possible to extract data by the same process as during a Blind SQL injection (i.e. character by character) as shown in the following script:

<script>
function http200()
{
alert("HTTP 200")
}

function http404()
{
alert("HTTP 404")
}
</script>
<script src="https://www.neoslab.com/labs/httpResponse.php" async="async" onerror=http404() onload=http200()></script>

The "httpResponse.php" file

<?php
if(rand(0,1))
{
http_response_code(200);
}
else
{
http_response_code(404);
}
die();

We can therefore tell the difference between the two responses thanks to HTTP codes and error handlers! The above mechanism for knowing whether a response is true or false is called Oracle XSS.

What use can we find in this method?

If the remote site has a user search system only available to the administrator, we can list these users by comparing the returns of the HTTP codes. The person connected must of course be the administrator of the site. Example of an attack scenario via an oracle XSS:

GET /admin/search.php?user=j* -> 200 // We found that "j" is our first character
GET /admin/search.php?user=ja* -> 404 // No user starting by "ja", so we go to next character
GET /admin/search.php?user=jb* -> 404
GET /admin/search.php?user=jc* -> 404
GET /admin/search.php?user=jd* -> 404
GET /admin/search.php?user=je* -> 200
---
snip
---
GET /admin/search.php?user=jean -> 200 // We finally found our user "jean"

CONCLUSION

Developers should never place sensitive content inside JavaScript files and also not in JSONP. Nevertheless, user entries that are saved to JSON files and read from them should be sanitized. To stop this kind of attack, we can use the following methods:

  • We add the header X-Content-Type-Options: nosniff to be protected from attacks on Content-Type.
  • We avoid putting user information in JavaScript files.