Cross-Site Scripting (XSS)

Browser-side security

We have seen how SQL injection can compromise the security of web application databases on the servers. There are other kind of attacks that work at the client-side. Web applications, as standard applications, usually have a state. For example, when we log into a web account a session is started and the web application remembers that we are authenticated giving access to our data and resources. This state needs to be represented in the browser in order to implement this session abstraction. This is usually done by storing a freshly generated session cookie that is sent to any subsequent request to the server. The cookie works as a session password that keeps us logged in during the session.

It is clear that if a session cookies is leaked someone else can hijack the session, impersonating the legitimate user. Thus, it is important that some browser-side protection is put in place to prevent attacks at the client-side.

The Same Origin Policy (SOP) (see, e.g., mozilla page on SOP) restricts access among documents or scripts loaded from different domains. Without SOP, in fact, browsing on a malicious site will allow it to access our session cookies and hijack any open session. Thus, SOP provides a simple form of isolation between web applications run on the same browser.

Even if SOP is in place, there are many ways to attack web applications at the client side. An important example is Cross-Site Scripting, in which the attacker injects a script directly in the web application so to circumvent the Same Origin Policy.

Cross-Site Scripting (XSS)

Cross-Site Scripting (XSS) attacks are a type of security vulnerability in which an attacker injects malicious code (e.g., HTML, Javascript) into web applications in order to leak sensitive information retained by the clients’ browsers accessing that site. Some examples of sensitive information are cookies and session tokens.

From wikipedia:

Cross-site scripting flaws surpassed buffer overflows to become the most common publicly reported security vulnerability, with some researchers in 2007 viewing as many as 68% of websites as likely open to XSS attacks.

There are two well known types of XSS vulnerability called Stored and Reflected XSS, depending on the persistence of the attack.

Stored XSS

Stored attacks are those where the injected script is permanently stored on the target servers (e.g., as a message in a discussion board). The malicious payload is automatically executed by the user’s browser when the infected page is visited.

Reflected XSS

When a web page includes some or all of the input sent to the server as part of the request, an attacker can forge malicious URIs that will “reflect” the attack back to the user’s browser.

In the typical scenario, users are tricked into clicking on malicious links sent via mail. When the request arrives to the vulnerable web server, the injected code is displayed as part of the rendered web page. The browser then executes the code because it cames from a “trusted” server.

Examples

Typically, an attacker is interested in injecting a malicious Javascript code enclosed in <script></script> tags to steal the session cookie of an authenticated user. If the web application doesn’t properly validate the input data, as shown below, the attack can be performed.

The following PHP snippet is a simple example of a vulnerable website. Notice that we set the X-XSS-Protection HTTP header to disable Cross-site scripting (XSS) filter built into most recent web browsers. We’ll see later (see Mitigations) why this is needed.

An attacker can inject arbitrary Javascript code by specifying the malicious payload as the value of either name or surname GET variables:

The resulting page will be:

Use haxor / xssleet to access the vulnerable website.

You can try to access session cookies via the following request:

To steal the user’s sensitive cookies, the attacker may provide to the victim a link similar to the one below. That URL, indeed, leaks the cookie values to a web site under the attacker’s control. Sometimes suspicious links are hidden in various ways, e.g. by using a URL shortener service like tinyurl.

The victim’s browser executes the injected code and passes the list of cookies to a malicious website via the cookie variable. Notice that %2b is the urlencoding of character ‘+’. By retrieving the results stored by the steal.php script (e.g., the pair HTTP referer, list of cookies) the attacker can lay his hands on the leaked information.

Filter evasion

Instead of performing proper input sanitization, unwary developers often rely on filtering out potentially dangerous keywords like script. Unfortunately, XSS attacks may be performed without using the script tag, for example using inline Javascript:

Other evasion techniques can be found in the OWASP XSS Filter Evasion Cheat Sheet.

Prevention

As mentioned before, most reflected and stored XSS can be addressed by performing proper validation and by escaping html characters on the server-side. In the case of PHP this can be done using either htmlspecialchars or htmlentities. There exist also libraries designed to cope with untrusted input supposed to contain HTML tags.

Further information can be found in the OWASP XSS Prevention Cheat Sheet.

Mitigations

To reduce the risk of revealing cookies via injected scripts, it is possible to prevent any Javascript code to access cookies by setting the HttpOnly flag. If this flag is included in the HTTP response header from the webserver, the cookies cannot be accessed by client side scripts.

This can be easily done in PHP via various facilities. An example follows:

If we try to access the list of cookies via the following request, as we did before, we should notice that SESSID2 is missing since it cannot be accessed by the running scripts.

Mitigation strategies are also implemented by web browsers. Even if browsers are defenseless against stored XSS since without a shared policy between the browser and the web application it is not possible to distinguish legitimate from malicious scripts, some effective countermeasures to attenuate the impact of reflected attacks have been developed. For instance, Google Chrome’s XSS auditor looks for code in the webpage that is found within the request. If a match is detected, the auditor raises an alert and prevents the injected script from being executed.

If we try to load the following resource using Google Chrome, by pressing F12 and displaying the “console” tab we should notice that the injection is detected:

The XSS Auditor refused to execute a script in 'https://xss.seclab.dsi.unive.it/greet_filter.php?name=%3Cscript%3Ealert(%22Hi%20there%22)%3C/script%3E' because its source code was found within the request. The auditor was enabled as the server sent neither an 'X-XSS-Protection' nor 'Content-Security-Policy' header.

The source code of greet_normal.php is exactly the same as greet.php, with the only exception that XSS filters are not explicitly disabled using the X-XSS-Protection header:

The XSS Auditor is effective in many situations when dealing with reflected attacks, but it should be considered only as an additional protection layer. Indeed, our toy page greet_filter.php can be still exploited and the XSS Auditor bypassed by splitting the attack payload among the two variables:

:)

Cross-Site Scripting attacks are traditionally assimilated to injections of malicious Javascript code. There exist, however, alternative techniques, such as HTML or CSS injections, which allow to achieve comparable goals to the ones of traditional XSS attacks!

Leave a Reply

Your email address will not be published. Required fields are marked *