When a software developer first gets exposed to web security he will inevitably memorize his first acronym: XSS. It stands for “cross site scripting” and it is one of the oldest vulnerabilities around. Its origins go way back to the 90’s when Javascript was the new kid around the block. XSS (back then it was CSS) was its evil little brother and it still thrives on its sibling’s success. One may wonder, “Why is it called cross site scripting?”. Well, initially it really was cross-site: a page had the ability to load another one and have read/write access to its DOM (Wow, can you believe that? More about this here). But those days are long gone, now we are armed with various browser security feature to combat this attack. Yet XSS is still a dominant vulnerability and it is not going away anytime soon.

Anatomy

Cross site scripting refers to the execution of malicious code in the browser. It’s important to note that this attack is not constrained to any browser or device. It affects everything that is capable of running Javascript. And while the actual exploitation happens on the client side, the server may also play a role in introducing the vulnerability! As you will see later on, most mitigation mechanisms must be deployed on the server. But before that, first we need to be clear on what we are defending against.

Types of XSS

We, as humans, love categorizing and naming things. In this case we came up with three categories. I’ll stick to the original categorization as that is widely accepted (more about this later). Let’s look at each one in detail.

Reflected XSS

The first, most benign one is called “reflected cross site scripting”. This happens when a malicious input is reflected back in the page content without the correct encoding (note that encoding here, does not refer to character encoding). As an example, think about a website which has a simple search form. You enter your search query and submit it. The server will receive your request and send back the results with a header stating what you searched for. The following image illustrates the point.

The process starts with the client sending a specially crafted request to the server. In our case it is a simple GET request with a malicious query string. When the vulnerable server processes this, it will echo part of the malicious request into the page’s source unencoded. Now, think about what happens next: The client’s browser receives the tainted response and parses it, in order to render the site for the user. During this procedure the injected unencoded input will be hit and the browser will interpret it as a script tag and execute its content causing a popup alert. Boom, you are hacked!

There are a couple of key concepts we must address.!

First, the attack has two phases: injection and exploitation. In this case, both of these happen in a single request-response cycle. The injection phase sends the malicious input to the server, while the exploitation phase happens when the browser processes the tainted response. From a hacker’s point of view this is a very strong constraint. Note that the injection has to be done by the victim. This makes it hard to scale the attack as it will only succeed if each victim goes through the injection phase and visits the maliciously crafted URL. If it is a regular request not containing the evil code, nothing will happen. So, why would anybody in their right mind visit such a URL? Ideally, nobody would do so! In reality though, it is a much more complex question. Users are manipulated into clicking such links or even better, these are requested automatically by the browser without the user’s knowledge, let alone consent. This brings us to the next point.

The attacker will need to find a way to execute the injection phase, mainly to get the victim to request the specially crafted URL. Users won’t just hack themselves, or will they? I will leave it to the reader as an exercise to think about possible distribution methods (hint: https://genuine-looking-site.com/index?parameter=<payload>).

Thirdly, the malicious request can contain the payload anywhere (it really depends on how the server processes the request). For an attacker, it is best if the payload is in the query string as that is easily transferred in the URL.

However it can be in the body or even the headers as well. Needless to say, the attack is not constrained to the GET verb either.

We nailed the basics down in this post, but surely reflected XSS is not the only type! Stay tuned, in our next post we’ll break down the other types.

This article originally appeared on the Emarsys Craftlab blog.