March 13, 2017 By Paul Ionescu 5 min read

In the previous three chapters of this series, we discussed ways for developers to put their hacker hats on and program defensively to prevent security bugs from cropping up in their software. We described the nature of SQL injection, OS command injection and buffer overflow attacks. We did not, however, touch upon the No. 1 issue that plagues web application developers: cross-site scripting (XSS).

Indeed, XSS ranks quite high in the CWE/SANS Top 25 Most Dangerous Software Errors list:

Rank Name
1 Improper Neutralization of Special Elements used in an SQL Command (‘SQL Injection’)
2 Improper Neutralization of Special Elements used in an OS Command (‘OS Command Injection’)
3 Buffer Copy without Checking Size of Input (‘Classic Buffer Overflow’)
4 Improper Neutralization of Input During Web Page Generation (‘Cross-site Scripting’)
Scroll to view full table

XSS is easy to test for. In fact, it is probably one of the most common vulnerability types found in software. However, XSS can be really hard to fix. When maintaining a large web application that was written 10 years ago using servlet technology, there may be thousands of places where XSS lays dormant. Newer technologies using rich, client-side user interfaces (UIs) are not spared, either.

To top it all off, most developers are using web technologies nowadays, even in mobile apps, so XSS is a big headache for everyone.

Notorious Examples of Cross-Site Scripting

XSS made history with the Samy worm, the fastest spreading virus of all time. The worm was a relatively harmless and very original type of virus that self-replicated by altering the profile pages of MySpace users and sending friend requests to its creator, now-famous hacker Samy Kamkar, who ended up in hot water with authorities after the incident. Twitter was also targeted by a similar XSS worm that embedded malicious links on the website StalkDaily.

Besides infections on social networking sites, XSS has been used for financial gain, most notably in attacks against e-commerce giant eBay. Cybercriminals injected malicious scripts into several listings for cheap iPhones. The scripts sent users to a spoofed login page that harvested their credentials.

What Is the Programming Flaw?

XSS occurs when a webpage renders user input as HTML or JavaScript code. Below are some examples of code that renders the user input.

Figure 1 shows several locations within the HTML markup of a server-generated page:

Figure 2 shows input rendered as is within the JavaScript code of a server-generated page:

Figure 3 shows XSS being rendered by client-side code:

The attack vectors come in many flavors. In the reflected XSS scenario, the attack is conducted via links that contain the malicious code. Victims click on the link, which is from a host they trust, and then interact with the altered website. Common attacks include fake login pages that send credentials somewhere else.

Figure 4 shows how reflected XSS works:

The stored flavor of XSS is even more dangerous because victims come across it unwittingly simply by using a vulnerable web application. The aforementioned XSS worms are examples of stored XSS.

Preventing XSS

There is no silver bullet to prevent XSS. In fact, fixing XSS sometimes feels like playing whack-a-mole. The video below exemplifies the challenges associated with preventing this pesky bug:

https://youtu.be/FGr6gGqM4f0

Let’s dive into a few best practices that web developers should always keep in mind.

Output Encoding

Output encoding works very well for pages generated on the sever side and is quite effective in neutralizing most XSS payloads. The most common method is HTML encoding, while URL encoding can help neutralize the injection of markup in links and redirects.

Figure 5 shows how HTML encoding neutralizes XSS:


JavaScript Escaping

Escaping can prevent injection within JavaScript context by escaping single quotes.

For example: x=”-alert (1)-” becomes x=’\’-alert (1)-\”

A flavor of HTML encoding that also encodes single quotes with ‘ can also be used. This provides a more consistent approach to preventing the issue.

Safe DOM Elements

XSS in modern, rich client UIs is often made possible by unsafe handling of the document object model (DOM).

Using the innerHTML attribute, for example, allows the user input to be rendered as HTML and XSS with JavaScript events. The safe alternative is to use contentText or innerText in some versions of Internet Explorer (IE).

Use Eval and Dynamic Function Calls With Care

Pages with large JavaScript libraries may be using the eval function, which accepts a JavaScript expression as argument. Needless to say, what goes into that expression should be carefully scrutinized. The same goes for situations in which the code or page generates function names dynamically.

Enforcing the Charset

There are XSS attacks that use a different encoding, such as UTF7, for example. If the charset of the page is not enforced, the browser will default to auto detect and those payloads will execute. For example: Content-type: text/html; charset=UTF8.

Input Validation

Whitelisting can reduce the attack surface, although in some cases single quotes and tags must be allowed. If you want to allow someone named O’Brien to update his or her user profile, for example, you need to allow single quotes.

If possible, most input should be whitelisted to alphanumeric to prevent XSS and many other attacks, and special characters should only be allowed on an exception basis. This will reduce the attack surface and minimize the potential for bugs.

Blacklisting is a very bad idea because it may prevent some tools or testers from finding the issue. Others may be able to beat the rule by trying a previously unknown method. The OWASP XSS Evasion Cheat Sheet lists the staggering number of XSS attack variations.

Mitigations

Besides preventing the issue, there are ways to minimize it by using secure headers that most modern browsers support:

  • X-XSS-Protection: 1; mode=block enforces the browser XSS filter for some browsers; and
  • Content-Security-Policy: script-src ‘self’ prevents the loading of external scripts, which makes XSS exploitation difficult.

There are many more useful settings of the content security policy, including options to log violations that can indicate that an attacker is leveraging a possibly unknown XSS on the site.

XSS Is Here to Stay

XSS is a pesky, ubiquitous and very dangerous type of programming flaw. Developers should always keep XSS in mind when building today’s flashy web applications. The web has become the choice for implementing attractive, platform-independent applications, and it is here to stay. Unfortunately, so is the threat of XSS.

Access Your Complimentary Trial

More from Application Security

What’s up India? PixPirate is back and spreading via WhatsApp

8 min read - This blog post is the continuation of a previous blog regarding PixPirate malware. If you haven’t read the initial post, please take a couple of minutes to get caught up before diving into this content. PixPirate malware consists of two components: a downloader application and a droppee application, and both are custom-made and operated by the same fraudster group. Although the traditional role of a downloader is to install the droppee on the victim device, with PixPirate, the downloader also…

PixPirate: The Brazilian financial malware you can’t see

10 min read - Malicious software always aims to stay hidden, making itself invisible so the victims can’t detect it. The constantly mutating PixPirate malware has taken that strategy to a new extreme. PixPirate is a sophisticated financial remote access trojan (RAT) malware that heavily utilizes anti-research techniques. This malware’s infection vector is based on two malicious apps: a downloader and a droppee. Operating together, these two apps communicate with each other to execute the fraud. So far, IBM Trusteer researchers have observed this…

From federation to fabric: IAM’s evolution

15 min read - In the modern day, we’ve come to expect that our various applications can share our identity information with one another. Most of our core systems federate seamlessly and bi-directionally. This means that you can quite easily register and log in to a given service with the user account from another service or even invert that process (technically possible, not always advisable). But what is the next step in our evolution towards greater interoperability between our applications, services and systems?Identity and…

Topic updates

Get email updates and stay ahead of the latest threats to the security landscape, thought leadership and research.
Subscribe today