October 4, 2005, dawned cold and clear--somewhere in the world, anyway. Bleary-eyed MySpace users woke from their slumber to log onto the world's dominant social media platform, eager to friend new people. People like Samy Kamkar. So eager for friends was Samy he dropped a cross-site scripting (XSS) exploit into his MySpace profile.
Now told and retold around campfires to young 'uns, the legendary lulz of Mr. Kamkar stand as a legacy to the fragility of web applications and failure to neutralize user input.
What is an XSS vulnerability?
At its most basic, an XSS attack involves an attacker entering malicious code into a web form or a web app URL to trick the application into doing something it's not supposed to do. Suppose a web application form asks you to enter your name, and instead you enter with glee:
<script>alert;("I'm a reflected XSS attack!")</script>
You click enter and see a pop-up message that says, "I'm a reflected XSS attack!" Now you know the gates to the citadel are wide open, and the guards are snoozing in the shade.
Few web applications in 2018 are that vulnerable, of course, but as the arms race between attackers and defenders escalates, attackers have found new chinks in web application armor to exploit. A successful XSS attack can cause severe and unpleasant consequences for you and your enterprise.
For a canonical definition, let us quote from scripture. Intone with me the holy words of the OWASP Top Ten:
Amen, hallelujah, and neutralize that input, please.
Mr. Kamkar was a script kiddie having some fun and whose intentions were clearly without malice, but the same kind of XSS vulnerabilities continue to plague more than two-thirds of all deployed web apps, according to OWASP, making it the second most common attack after SQL Injection.
The term "cross-site scripting" has morphed in meaning over the last 15 to 20 years, so much so that Mitre now prefers the less pithy, but more precise, "improper neutralization of input during web page generation." Neutralize that input, folks. Neutralize it with extreme prejudice.
Repeat the mantra after me: Don't trust user input. Don't trust user input. Don't trust user input.
You may not find nirvana, but you will scorch the earth for low-skilled attackers. XSS is a well-understood attack vector that's ancient in internet years. If you're not defending against these attacks, you're not doing your due diligence.
Types of XSS
Like Gaul, which Julius Caesar famously divided into three parts, XSS attacks are also consist of three somewhat overlapping regions: reflected XSS (not persistent), stored XSS (persistent), and document object model (DOM)-based XSS.
Reflected XSS is often used as part of phishing schemes, and it is both the easiest to exploit and to prevent. The <script> above is a rudimentary example of reflected XSS: An attacker injects malicious content into an HTTP request and the results are then "reflected" back to the user.
Of course, an attacker is unlikely to want to exploit themselves (that's some Freudian shrink head stuff right there), but an attacker who can trick a victim into clicking such a link can hijack their session. As a result, reflected XSS is commonly found in phishing attacks.
For instance, an attacker might craft a malicious URL that exploits a vulnerable web application and then use phishing or other social engineering techniques to trick a legitimate user of the web application to click the malicious link. The web application would then reflect the malicious code back to the victim, which can then execute malicious code in the victim's web browser.
Stored XSS (or persistent) attacks happen when an attacker tricks a web application into storing malicious code in the web application's database. Once stored on the server, that malicious code can attack the system itself or deliver malicious code to many, or even all, of the web app's users. A common example is posting malicious code in the comment section of blogs (back when blogs were still a thing).
<script>alert;("I'm a persistent XSS attack in a blog comment!")</script>
Anyone who visited the blog would be a victim of that malicious code. That's why persistent XSS is the most dangerous kind of cross-site scripting attack. Why attack one user when you can attack them all? Smart gangsters and spies look for economies of scale.
Trust issues: Cross-site scripting prevention
Remember the mantra: Don't trust user input. Your web application should have trust issues with user input, and that's not likely ever going to change. The good news is, XSS is an oooooold attack vector and the defensive tools you need are mature and easy to use. Use them.
Whitelist trusted input. Blacklist is fragile and will eventually fail. Decide what constitutes safe input for your web application and reject or escape the rest. "The first rule is to deny all," [their emphasis] OWASP writes. "The reason for Rule #0 is that there are so many strange contexts within HTML that the list of escaping rules gets very complicated."
The OWASP Top Ten XSS Prevention Cheat Sheet goes far deeper than we can here, and you should read the whole thing. Remember to pen-test your app regularly to make sure it is not vulnerable to XSS attacks.
What is the difference between XSS and CSRF?
Cross-site scripting (XSS) and Cross-site request forgery (CSRF) are related attacks that target a victim's browser. The main difference is that CSRF exploits a user's authenticated session (maybe they are logged into their bank account), and that XSS doesn't need an authenticated session to be effective.
Let's say you were logged into Twitter and online banking at the same time, and you clicked on a Twitter link that looked like this:
Depending on how your bank manages session tokens, and what browser you're using, you might be five grand poorer.
XSS is a more dangerous attack vector, but it's important to defend against both XSS and CSRF. You can read more about CSRF defensive security measures at the OWASP CSRF Prevention Cheat Sheet.
When XSS attacks
Cross-site scripting (XSS) is low-hanging fruit for attackers looking to exploit web applications, but it is easily mitigated by performing due diligence. The Samy worm was a good-natured hack that hurt no one. The same class of vulnerability is used daily by spies and gangsters with malice aforethought. More than a decade after the Samy worm dropped, failure to mitigate the risk of a XSS attack begins to look like gross negligence.