App Security: Introducing Cross-Site Scripting

By Kellen 

When it comes to weaving together distributed applications, backends, and services, many developers wonder whether their applications become more vulnerable to common exploits. Whether that's the case or not, if you're putting any service between your applications and your user-base, you should have a solid understanding of some common vulnerabilities.

Hack the Planet!

The web has evolved from its static roots into robust, wild, and tangled dynamic applications. While offensive computing is nowhere near as radical as [ZeroCool and the Gang]( made it seem in the 90s, malicious actors are in heavy supply. Developers of all skill-and-stack levels should know the basics of application vulnerabilities. We'll start with that then roll into Cross-Site Scripting, or XSS.


Web Application hacking is less brute-force and more cloak-and-dagger. In most cases, applications are exploited by swindling the web server into thinking that something malicious was the typical, safe input that it expected. HTTP works through request and response; this is a by-product of ephemeral HTTP connections and the distance between the client and the server. It is within this exchange and over this distance where trouble is often afoot.

Thanks to Transport Layer Security (TLS), the tunnel that encapsualtes HTTP to make an HTTP*S* connection, the traffic in transit can be considered relatively safe from prying eyes. This shifts the attack vector. Assuming safer pipes, the client and the server are where someone would start poking.


Security is an ever-shifting endeavour. Taking the time to fully under-stand the flaws of your architecture can be fruitless. In each component update and change to your code you've shifted the playing-field. Due to this volatiltiy and the lack of up-front reward for good security when compared to a desirable feature, it's no surprise that security is often left up to a week-long consultancy near the end of a product life-cycle. Afterall, if the Conjoined Triangles of Success taught us anything, it would be compromise.


Security threats can range from disruptive: a Distributed Denial of Service attack causing service blockages and an inflated hosting or CDN bill, to catastrophic: thievery of customer information or exploitation of business logic to steal information or money. Any sort of system distruption is a critical event but those that shake the integrity of information security have lasting consequences.

As anyone who has ever taken Kali Linux for a whirl knows, there are many weapons with which one can mount a cyber-attack. Luckily for the developer, there are just as many shields and defensive practices. The most important tools are: a deep understanding of your own systems, code and libraries, fully aware monitoring, and last but not least: application logic that limits client access and appropriately sanitizes inputs.

It is user input that is the trojan-horse that enables modern XSS attacks to take place. Visitors send in a nice wooden horse (or rabbit) of unique content but out may spring ne'r-do-wells clad in nasty JavaScript. Without further ado, onwards to XSS.


Three Kinds o' Nasty

Most modern web applications provide an encrypted cookie to a visitor to confirm that they have logged in; the cookie is a unique, tokenized key-pass that renables access to a user's privatized data. Once the user receives this token it's attached to each subsequent user request. It verifies the user's identity until the session has been ended or the cookie expires.

There are three different kinds of XSS attacks. The end-goal is the same: trick a user into sending their active token to the attacker. Once the attacker has this token they're free to do what they wilt with the user's account. XSS attacks are some of the nasiest and most common and are considered by many the Holy Grail of application attack.

Reflected/First-Order XSS

Depressingly, most exploitations work because they abuse trust. Browsers have baked in trust-based protection around the same-origin policy. It is because of the same-origin policy that one is protected in a case where...

Someone has a site where they perform ill-activities: stealyourpassword.~~~. If you have an active session token to trusted-site.~~~ and you happen to visit stealyourpassword.~~~ they won't be able to run scripts to steal that token because the domains do not share the same origin. Browsers ensure that a script executing from stealyourpassword.~~~ should not be able to yoink your trustedsite.~~~ session.

The same-origin policy is useful for preventing inter-domain shenanignas. HTTPS is useful for preventing inter-connection shenanigans, between the client and the server; if you don't have HTTPS, imagine how easy it would be to hoodwink users into clicking on a phony URL that would jack their session. It is a simple matter of intercepting and adjusting packets in transit, a relative cake-walk when things zip around in TLS-less plain-text.

But even with these things we're still vulnerable, as we see in the XSS dance...

The user has been... Dramatic pause... owned.


Stored XSS

Richness is the rage. Many popular pages revolve around the idea of user-generated content. We identified user input as a key area of weakness within modern applications. Our first XSS example didn't involve user input - it inolved exploiting server output. Most browsers and frameworks fix that vector out of the box, preventing weird JavaScript from winding up in URIs ripe for exploitation.

A stored XSS attack is one where the content, as the name and section introduction imply, is stored within the server after being placed there by an attacker. An application that allows the submission of any content is vulnerable; whether the content is public or private to the user matters not, the idea is similar to that of Reflected/First-Order XSS: you want an un-suspecting person to click a bogus link.

This is how Stored attacks shake out...

... Owned!


Trust: exploited. These attacks are more subversive than Reflected/First-Order attacks because they abuse the basic assumption of trust that a site go-er has. The average user will not assume ill-nature when browsing content within a trusted domain.


To understand DOM-Based XSS, one must understand a fundamental piece of client-side JavaScript: the Document Object Model. First, the flow:


Deliver Us, Serenity

XSS attacks are alive and well. There have been many high-profile exploits, including Facebook and LinkedIn. When you see how they work it becomes clear that one needs to pay careful attention to sanitizing what users are able to input into their applications.

While Reflected/First-Order XSS attacks have largely been mitigated by the constant wave of application framework and browser improvements, Stored and DOM based attacks happen everywhere developers are strapped for time -- which is to say... everywhere.

XSS vulnerabilities reveal an unfortunate reality: your users will be hoodwinked. Assume that a user will click on something malicious. Whether it's within your own pages, such as with Stored XSS attacks or targeted through some social engineering crookery, users will click bad things. As application development evolves, one hopes we can create better safety nets.

Let's thread back into the original premise. If you're using a delivery network of some kind, does that make your applications more vulnerable to XSS-based attacks? Theoretically, no. For there to be an increase in danger there would need to be an increase in the likelihood that a user could impersonate a trusted domain in order to get it to vouch for bad code. There is no evidence of that being the case. Although, as is the case with any service you use, you need to apply a degree of trust.

Fly started when we wondered "what would a programmable edge look like"? Developer workflows work great for infrastructure like CDNs and optimization services. You should really see for yourself, though.