Cross-site scripting (XSS) is one of the most dangerous vulnerabilities in web applications. It is a client-side script injection technique that attackers can use to steal information or send malicious requests to a server. There’s no fixed way of executing an XSS attack — it all depends on how an application was built and the creativity of attackers. This makes it difficult for organizations to set up complete protection against such attacks. But before you set up a defense, you need to understand how the attack works.
This blog post looks at different types of XSS attacks and how they work. Let’s start with learning more about XSS.
What is cross-site scripting (XSS)?
A web application can be divided into two major divisions: the server side and client side. Server side refers to the servers, databases, and internal network of the organization. Client side is where users access the application from. When we say client, we usually mean the software (e.g., browser) that is used to access a web application. Communication between server and client happens through requests and responses. An XSS vulnerability exists if attackers can inject malicious code on the client side and make requests successfully.
An XSS attack is when attackers inject malicious client-side scripts into web pages that are accessed by other users (victims). So, if you inject a malicious script into a web page, when someone views that web page, the injected code executes on their browser. Thus, attackers can gain access to sensitive information stored in a user’s browser, such as cookies. If the victim has admin privileges, then an attacker might also gain access to special features of the application.
How does XSS work?
Let’s look at an example. Suppose a webpage takes input from the user and displays that input on the webpage. It could be as simple as asking the user for their name to display a greeting. Behind the screen, the application takes input from the user, stores the input in a variable, and then uses the variable to display the user’s name in the result. The sample code would look something like this:
input.html
output.php
The line of code we’re interested in here is: echo '<p>Hello, '.$Name.'. Welcome to xyz.com.<p>'
. This line converts to the following in the browser:
<p>Hello, John. Welcome to xyz.com.<p>
The code stores the user’s input in the $Name variable and uses it to display their name. Now, what if instead of giving their name as input, the user enters a malicious string? Let’s say they’re using a script tag in the input as follows:
<script>alert(1)</script>
When they enter this text as input and submit, the program stores it in the variable and sends it to the browser as a result:
<p>Hello, <script>alert(1)<script>. Welcome to xyz.com.<p>
Here, a part of the response to the browser is inside script tags, so the browser considers it as a script to be executed and will execute the alert function, creating an alert box. When an attacker sees this, they know that this means that the application is vulnerable to XSS attacks.
XSS in real life
In the above example, we saw how attackers use the input field to execute a JavaScript function. But an attack that causes the browser to display an alert wouldn’t do any harm. Let’s suppose that instead of the alert function, the attacker could run some other script that does something dangerous. For example, an attacker could use a script to fetch the cookies stored in the victim’s browser and send them to the attacker’s machine. The attacker could then use those cookies for session hijacking.
XSS attackers make a malicious script part of a web page to send it to victims. When victims open the webpage, the malicious script executes.
Now that you know how XSS works, let’s dive deeper and look at different types of XSS attacks.
Types of cross-site scripting (XSS) attacks
Based on where an attacker places an injection for execution, XSS attacks can be divided into three types: reflected (nonpersistent), stored (persistent), and DOM-based XSS attacks.
1. Reflected (non-persistent) XSS
Reflected XSS is one of the most common types of XSS. To execute this type of invasion, attackers craft malicious links, phishing emails, or use various other techniques to trick victims into sending malicious requests to the server.
The victim unknowingly sends the malicious script as a part of the usual request to the server from the client, as in the example we showed you earlier where the user sends their name. If the application isn’t using proper escaping to insert user-provided data in an HTML context, the application will send the malicious script as a part of the response. When the server’s response loads on the victim’s client, it also loads and executes the malicious script on the client.
In the earlier example, when the name is sent as a part of the request, the name is stored in a variable in the script for processing. But the server doesn’t store the name anywhere after responding to the request. It just processes it and immediately returns it back to the client. Similarly, when a malicious script is a part of the request, the server will process the request and immediately send a response back along with the malicious script.
In this type of XSS, the malicious script is reflected from the server back to the client. Hence, it is called reflected XSS. If an attacker wants to use reflected XSS, they have to send the payload to each victim. Hence, reflected XSS is also known as non-persistent XSS.
2. Stored (persistent) XSS
The title of this XSS kind of tells how it works. The term stored indicates that the payload is stored somewhere. In stored XSS, the payload is stored on the server side. Once the payload is present within the application, provided it wasn’t properly escaped by the developer when it was prepared for display, anybody accessing the part of the application that contains the payload would trigger the malicious script.
Let’s say you have a video channel on an application that is vulnerable to XSS. Your subscribers can watch your videos, like them, and also leave comments. The application stores all the comments in a database. Suppose you have a video on cybersecurity and there are a hundred comments on it. Whenever a user visits this video, the application fetches all the comments and displays them on the webpage.
Now, suppose that one of these comments is not just a comment, but is instead a malicious script injected by a hacker. The application will store the malicious script in its database and send it to every user who views the video. The victim’s browser then executes the malicious script when it loads the page.
In the case of stored XSS, the attacker injects the malicious script just once. After it’s stored, the application delivers the payload to all users accessing that part of the application. Thus, it is also called persistent XSS.
3. DOM-based XSS
This type of XSS vulnerability exists only if an application uses a Document Object Model (DOM). When an application uses a DOM to store data, the data remains only on the client side and the browser reads and displays the output. Data stored in a DOM is not sent to the server.
In a DOM XSS, an attacker injects the payload in the DOM (via the URL or any sink used by the browser’s API). When a user visits the page at that URL or triggers an action on this page, the browser updates the DOM to include the attacker-provided script. That’s when the application executes the payload.
And that brings us to the end of this post. You’ve learned about three different types of XSS: reflected, stored, and DOM-based XSS attacks. But is understanding them enough? Definitely not. As a security professional, you should be very careful to make your application secure against such attacks. So, what next?
XSS mitigation
XSS attacks bring out creativity in attackers. This cheat sheet gives you a glimpse of the various injections attackers use. Initial steps to protect against XSS attacks include input sanitization and data encoding. But you should also continuously monitor and protect your application against exploits or attempts. Using an application security management platform could be a great help to you. You could also organize bug bounty programs to learn about bugs and gaps you may have missed in your application security.
Hackers are getting smarter and more creative, so your best bet is to implement several layers of security. It’s safest to take all the measures you can to detect and protect against XSS attacks and other security issues. To get visibility into your application security, and monitor and protect against XSS attacks and many others, check out Sqreen.
This post was written by Omkar Hiremath. Omkar is a cybersecurity analyst who is enthusiastic about cybersecurity, ethical hacking, data science, and Python. He’s a part time bug bounty hunter and is keenly interested in vulnerability and malware analysis.