Skip to content
Close
Login
Login
Khaled Yakdan 5 min read

What Is Cross Site Scripting and How to Avoid XSS Attacks?

Cross-Site Scripting (XSS) - Risks and Countermeasures

Cross-site scripting has been at the top of the OWASP Top 10 for nearly a decade. In this article, we'll explore everything you need to know about XSS, the associated risks, and countermeasures you can take. 

Cross-Site-Scripting

This article is about:

How Does Cross-Site Scripting Work

Cross-Site Scripting (XSS) is an attack during which a malicious actor tries to insert snippets of code into dynamically generated websites. When those websites are delivered to the user's browser, the injected script can modify the look and behavior of it and even take actions in the background without the user knowing it. When thinking about online banking or other platforms one may routinely log in to, it becomes clear that this can pose a significant threat. 

Once the script is injected into the page, web browsers have no way to tell it apart from the other legitimate scripts that are served along with it. That's why it's extremely important that the web applications themselves implement countermeasures and are regularly dynamically tested under real-world conditions to check if they hold tight.

Jon<script>alert(‘XSS!’);</script>Doe

Generally, any website or application is vulnerable to Cross-Site Scripting if it uses unsanitized user input in the output it generates. Sometimes, the malicious script is also stored in the web application or in a database. However, the final goal is always to deliver the script to a client's browser, where it is executed to perform actions. XSS attacks occur when user input is accepted as part of a request and then used in the output without proper encoding for validation and sanitization.

The most simple example of this can be shown with a website offering its users to create an account. Of course, we'll need to pick a username. A crafty attacker might start by trying things like “Jon<script>alert(‘XSS!’);</script>Doe”. Since usernames are often displayed in many places and shown to other users of the web application, this is an ideal target. If the server doesn't take care of sanitizing the "<script>" tags, the attacker can now execute code in other people's browsers.

How XSS Occurs

To perform XSS, attackers first need to find a way to inject the malicious code (payload) into a website the victim visits. The execution can be triggered in other ways when a webpage loads or a user hovers over specific elements, such as hyperlinks.

If the website or app lacks proper data sanitization, the malicious script executes code on the victim's system. Since the script comes from a seemingly trusted website, the victim's browser runs it without questioning its legitimacy.

Since the malicious script acts on behalf of the trusted website, it will be able to access potentially sensitive information stored on the client's browser, including session tokens and cookies.

Types of XSS Attacks

XSS comes in three primary flavors: stored, reflected, and DOM-based XSS attacks.

  • Stored XSS is also known as a persistent or Type-1 XSS. Here, the attacker injects a payload and saves it in the website or web application database. The malicious script is executed alongside the site's legitimate code during a request.

There is another subcategory of stored XSS attacks known as Blind XSS. With a blind XSS attack, the attacker targets a part of the system that he himself cannot access and thus cannot check immediately if the injection was successful (hence the name "blind"). A target for this could be a contact form whose content is later displayed to an administrator and not to the clients. 

  • Reflected XSS is also known as non-persistent or Type-2 XSS. In reflective XSS attacks, the hackers do not store the payload in the application or website's infrastructure. Instead, it is reflected off the server as a response to a specifically crafted link.

Reflected XSS is much more widespread in web applications and is considered to be less harmful as it is a one-time attack where the payload is only valid on one request.

  • A DOM-based XSS attack occurs when users click on a link created by an attacker. Attackers then embed the payload into the malicious URL link. From there, it is passed to the browser's Document Object Model (DOM), where it is executed. This happens because the browser interprets the request as coming from a trusted website or application.

Why Websites Are Susceptible to XSS-Bugs

XSS attacks are possible in pretty much any client-side programming language, including ActiveX, VBScript, and Flash, but they are most common in JavaScript. Some people may find this difficult to agree with, given the controlled environment JavaScript files are executed in and their limited access to the operating system.

While JavaScript is a powerful language for building dynamic web applications, it's equally powerful for attackers when they are able to inject their own code, as it allows attackers to access large parts of the entire web backend.

Moreover, JavaScript-based XSS attacks have far-reaching consequences. For instance, website defacement since the injected malicious script can modify the content displayed by the browser. In more severe cases, criminals can change a product's documentation or alter a press release to ruin the reputation of a target company. Industry specialists recommend thorough testing of Java applications (for vulnerability and flaws) using negative testing tools that can handle their complexity.

The Aftermath of XSS Attacks 

The damage caused by a successful XSS attack varies from a petty nuisance to significant security risks, depending on the sensitivity of the data handled by the vulnerable site and the nature of any security mitigation implemented by the site's owner.

Generally, potential consequences of Cross-Site Scripting attacks (for end users, website owners, and developers) include:

  • Redirecting users to malicious websites
  • Stealing usernames, and passwords, thus compromising a victim's account
  • Modifying or defacing the affected sites
  • Running web browser exploits (e.g., crashing the web browser)
  • Financial loss/fraud
  • Credit card information theft
  • Reputation damage
  • Customer churn
  • Incident response and recovery costs
  • Compliance fines
  • Legal costs, including lawyer fees arising from potential lawsuits for contract violation and liability, as well as customer reimbursement

9 Tips to Protect Yourself Against XSS Attacks

Here are some tips that will help you successfully mitigate Cross-Site Scripting:

1. Make Sure Dependencies Are Up-To-Date

As a general rule of thumb, adopt effective patch management or vulnerability management programs and ensure that you install high-priority and critical patches as soon as they are released. In addition, look out for blocklisted code libraries, minimize third-party code dependency, and always ensure you have secure access to code libraries.

2. Run Regular Security Audits

Even if you follow all the best coding practices, slight mistakes during core development or updates will inadvertently introduce an XSS vulnerability. Thankfully, when you scan your websites or applications regularly for vulnerabilities, you can quickly identify a loophole and fix it before it becomes a big problem.

3. Set Up a Firewall

Another way to avoid XSS attacks (as well as various other attacks) is by using a web application firewall that continuously scans and intercepts any activity that seems like an XSS attack, giving your site an extra layer of protection. However, WAFs do not offer 100% protection and should be your last resort—being secure by design is considered the best practice.

4. Validate User Input

Another great way to prevent XSS attacks is to validate every input field. Consider limiting user input to a specified list whenever you can. For instance, you can require all content to be alphanumeric and block HTML or tags used in XSS.

5. Encode Output Data

At the point where user-controllable data is output in HTTP responses, encode the output to keep it from being interpreted as active content. Depending on the output context, this might require applying combinations of URL, HTML, JavaScript, and CSS encoding.

6. Create a Content Security Policy (CSP)

Creating and implementing a content security policy (CSP) is an effective way of mitigating Cross-Site Scripting and other vulnerabilities. It prevents XSS by white-listing URLs from which browsers can load and execute scripts. The server prevents the client's browser from executing any script from an untrusted URL. The CSP acts as an allow list where only domains listed can run while everything else is blocked.

7. Use Safe Cookies (e.g., HTTP only)

Malicious JavaScript can be used to steal cookies containing users' session IDs. And since there is hardly the need to manipulate or read cookies in client-side JavaScript, consider marking cookies as HTTP-only. This means that cookies can only be received, stored, and sent by the user's browser but cannot be read or modified by JavaScript (including malicious JavaScript). You may also want to adopt other stringent cookie rules, like tying them to a specific IP address, to keep attackers from using them during XSS attacks.

8. Test Your Software Continuously (Including Negative Testing)

Testing can help you identify and fix bugs and security issues early. To prevent XSS and other injection vulnerabilities, negative testing approaches like feedback-based fuzzing are highly effective. Compared to a unit testing approach, in which testers approach the system under test with a hunch of where the issues may lie, fuzzers test systems using unexpected and unusual inputs while constantly refining test inputs based on code coverage feedback from the system under test. For larger projects, it is considered best practice to integrate feedback-based fuzz testing into the C/CD pipeline, to run tests continuously (e.g., at each pull request).

How to Prevent Cross-Site Scripting With Feedback-Based Fuzzing

Fuzzing is an automated software testing technique that injects invalid, malformed, or unexpected inputs into a system to find software defects and exploitable software vulnerabilities, including XSS.

Feedback-Based Fuzzing

Feedback-based fuzzers instrument the tested software to collect data about its interaction with test inputs/requests. This data is then sent back to the fuzzing engine, where it is used to craft further, more refined test inputs that can traverse larger parts of the source code. This allows feedback-based fuzzers to increase code coverage while uncovering vulnerabilities that are deeply hidden within the system under test.

Since feedback-based fuzzers test applications during execution, they always spit out the crashing input when they find a bug, making it easy to fix it.

Example of an XSS-bug found with Fuzzing WebGoat

How to Fuzz Your Own Code

If you want to learn more about how fuzz testing can help you alleviate XSS vulnerabilities and other OWASP Top 10 vulnerabilities, you should check out jazzer.js, an open-source fuzzing tool for JavaScript applications. 

If you are looking for more firepower, you can also check out our Code Intelligence testing platform for CI/CD-integrated fuzz testing in C/C++, Java, Go, JavaScript, and many more languages. Integrating feedback-based fuzz testing into your CI/CD will speed up your development process while giving you the means to find and fix vulnerabilities long before they ever make it into a finished product.

Learn More