Products

Solutions

Resources

Search for API Security Tests

XSS: What is Cross-site scripting (XSS) and how to prevent as a developer?

This blog will help developers to understand XSS, its types, how to discover and prevent it. XSS stands for Cross-Site Scripting, a type of vulnerability

What-is-XSS
What-is-XSS
What-is-XSS
Author Image

Jaydev Ahire

10 min read

Introduction to XSS

Do you remember when the Microsoft Exchange server was found to have a vulnerability that allowed for a Reflected Cross-Site Scripting (XSS) attack? This RXSS could have led to unauthorized access to email accounts, phishing attacks, and other actions that could change the state of the affected application. XSS attacks pose an especially grave danger, as they enable attackers to execute malicious code within the user's browser, potentially resulting in the theft of sensitive information or even complete account takeover. Nevertheless, Microsoft has addressed the issue by releasing a patch to fix the vulnerability. This underscores the importance of keeping software up-to-date and regularly checking for security vulnerabilities.

In this blog, we will learn :

  1. What is Cross-site scripting (XSS)?

  2. Types of XSS

  3. How to find XSS vulnerabilities proactively?

  4. How to prevent XSS

What is Cross-site scripting (XSS)?

XSS

XSS stands for Cross-Site Scripting, a type of security vulnerability that allows attackers to inject malicious scripts into a web page viewed by other users.

What happens if a web application has XSS? When a user visits an application that has a cross-site scripting vulnerability, the attacker's script gets executed by the user's browser. Unfortunately, this allows the attacker to get their hands on sensitive information such as login credentials, session tokens, or personal data. This can also enable other malicious actions, such as manipulating the content of the page, redirecting the user to a malicious website, or infecting the user's system with malware. The possibility of danger is endless!

XSS has multiple layers to it. Let’s deep dive into the types of XSS in the next section.

Types of Cross-site scripting (XSS)

There are three types of XXS:

1. Reflected XSS:

In 2019, a security researcher discovered a reflected XSS vulnerability in Google Translator. This vulnerability let attackers inject harmful code into translated text, which could then be run when other people viewed it. Check this image below!

Reflext XSS

Reflected XSS is a type of cross-site scripting vulnerability that occurs when an application echoes back user input in the response without properly validating or encoding it. This attack typically involves an attacker crafting a malicious link or form containing a script. When the victim clicks the link or submits the form, their browser executes the script.

Example Scenario: Suppose you have an API endpoint that retrieves a list of articles based on a search query. The server then returns the list of articles in a JSON response that includes the article title, author, and content. Here's an example of the vulnerable code that echoes back the user input without proper encoding or validation:

Reflected XSS Example

In this example, the $search_query variable is not sanitized or validated, and it is directly included in the JSON response returned to the user, making it vulnerable to reflected XSS attacks. Now how does the attacker perform reflected XSS here? An attacker could craft a malicious URL that includes a script as the query parameter. See below:

Reflected XSS example 2

What happens if a user sends the request? The victim's browser executes the script, displaying an alert box with the message "XSS". An attacker can use this to steal the victim's session cookies, passwords, or other sensitive data or perform other malicious actions. Dangerous!

Don’t worry! you can prevent this by using input validation in your code. Here’s how you can sanitize and validate all user input and encode any special characters before including them in the response.

For example, the following code snippet uses the htmlspecialchars function to sanitize the user input:

Reflected XSS example 3

In this improved code , the htmlspecialchars function expertly encodes any special characters in the user input, such as < and >, before including it in the JSON response. This input validation technique effectively prevents the browser from mistakenly interpreting the input as HTML or JavaScript code and displaying it as plain text instead. Read on as I will be discussing more techniques of input validation throughout the blog.

2. Stored XSS:

In 2018, a security researcher discovered a stored cross-site scripting (XSS) vulnerability in Snapchat that allowed attackers to inject malicious code into business.snapchat.com. The vulnerability could have allowed an attacker to steal user credentials or perform other malicious actions.

Stored XSS example

Stored XSS, also known as persistent XSS, is a cross-site scripting attack where the malicious code is permanently stored on the target Application's database or server. Unlike reflected XSS, where the malicious code includes in response to a user's request, stored XSS attacks can affect all users who access the vulnerable page or resource. Stored XSS attacks occur when an attacker can submit malicious data to a website, such as through a form or comment field, that is then stored and displayed to other users.

Example Scenario: Suppose you have an API endpoint that allows users to submit comments on an article. The server then stores the comments in a database and returns them in a JSON response, including the comment text and author. Here's an example of the vulnerable code that stores the user input without proper encoding or validation:

Stored XSS example

The $comment_text and $author variables are not sanitized or validated in this example. They are directly included in the JSON response returned to the user, making it vulnerable to stored XSS attacks. An attacker could craft a malicious comment that includes a script like below:

Stored XSS code snippet

The payload is an HTML img element with the src attribute set to x, which is not a valid image source. When the browser tries to load the image, the onerror event is triggered because the image cannot be loaded, and the JavaScript code inside the onerror attribute is executed.

In this case, the JavaScript code sets the src attribute of the img element to a URL that includes the victim's cookies as a parameter. The document.cookie property is a string that contains all of the cookies associated with the current document, including the session cookie that identifies the user to the web application.

The URL in the payload points to a web server controlled by the attacker (http://192.168.0.1:8888/), and the cookies are included as a query string parameter (?cookies=<cookie_value>).

When the payload is injected into a vulnerable web page, and a victim visits the page, their browser will send a request to the attacker's server, including their session cookie as a parameter. The attacker can then use this cookie to impersonate the victim and perform actions on their behalf within the web application. Account takeover!

Don’t worry! you can prevent this by using input validation in your code. Here’s how you can sanitize and validate all user input and encode any special characters before storing them in the database.

For example, the following code snippet uses the htmlspecialchars function to sanitize the user input:

Stored XSS

In this case, we sanitize the $_POST['comment'] and $_POST['author'] variables using the htmlspecialchars function with the ENT_QUOTES and UTF-8 parameters to escape any special characters that could be interpreted as code by the browser.

3. DOM XSS:

In 2022, a security researcher discovered a DOM-based cross-site scripting (XSS) vulnerability on the TikTok advertising platform ads.tiktok.com. The vulnerability allowed an attacker to inject malicious code into the platform's landing page and execute it within the user's browser. This could have potentially allowed an attacker to steal user data or perform other malicious actions.

XSS

DOM-based Cross-site scripting (DOM XSS) is a type of cross-site scripting vulnerability that occurs in the Document Object Model (DOM), which is the data representation of a web page in the browser. In a DOM-based XSS attack, the malicious payload is executed due to modifying the DOM environment in an unsafe way rather than through a traditional injection into the HTML source code or reflected in a response from the server.

The payload in a DOM-based XSS attack is often included in the URL or as part of the client-side code, and it is typically executed when the victim interacts with the page in a specific way. For example, the payload may be triggered when the victim clicks on a link, submits a form or enters text into an input field.

Here's an example of a DOM-based XSS vulnerability in JavaScript:

Example of XSS

In this example, the user is prompt to enter their name into an input field and click a button to submit the form. When the user clicks the button, a JavaScript function called greet() executes. This function retrieves the value of the name input field and uses it to generate a personalized greeting message, which is displayed on the page.

However, there is a potential vulnerability in this code. If an attacker can manipulate the value of the name input field to include a script tag, they can inject malicious code into the page and execute it in the victim's browser. For example, an attacker could enter the following input:

XSS example

In this example, the attacker injects a script tag into the page that displays an alert box with the text "XSS!".

Here's an example of how input validation and output encoding can prevent DOM-based XSS vulnerabilities in JavaScript:

XSS example

Here, the developer has updated the greet() function to include input validation and output encoding in this example. The input validation step removes script tags from the name input field, preventing injected scripts from executing. The output encoding step uses the encodeURIComponent() function to encode the value of the name variable, preventing any special characters from being interpreted as executable code.

Using input validation and output encoding is one way to prevent DOM-based XSS vulnerabilities.

It's important to keep in mind that the attack scenarios and code snippets presented above are simplified illustrations for developers to understand the preventions of XSS vulnerability. The validation/prevention process may be more complex in real-world scenarios.

Test for XSS using the best proactive API Security product

Our customers love us for our proactive approach and world class API Security test templates. Try Akto's test library yourself in your testing playground. Play with the default test or add your own.

How to discover XSS vulnerabilities proactively ?

One approach to proactively get automated alerts on XSS vulnerabilities is using a code-level detection tool like Semgrep. This tool can be integrated into the development process and scan code for potential vulnerabilities before they reach production. By catching issues early on, developers can fix them before they become more serious problems. Additionally, setting up regular security scans using security testing tools such as Akto and implementing strict security policies can help further reduce the risk of XSS attacks.

How to prevent Cross-site scripting (XSS)?

As a developer, you can do the following to prevent XSS:

1. Content Security Policy (CSP): Use a CSP to restrict which scripts to execute on a web page and from where those scripts load.

CSP

In this example, the default-src directive sets the default source for all types of resources as the current origin ('self'), meaning that scripts can only load from the same origin as the page. However, scripts can also load from https://trustedcdn.com, which is a trusted content delivery network.

The script-src directive further restricts the sources from which scripts load to only the same origin and https://trustedcdn.com. This means that the browser will block any attempt to load a script from a source that is not explicitly allowed by the CSP. This helps to prevent cross-site scripting attacks and other types of script-based attacks.

2. Properly configure and secure cookies: Use the HttpOnly flag and set the Secure flag to ensure that cookies are not accessible by client-side scripts and are only transmitted over HTTPS. Set the HttpOnly and Secure flags to configure and secure cookies properly. The HttpOnly flag prevents client-side scripts from accessing the cookie, which helps protect against cross-site scripting (XSS) attacks that could be used to steal cookies and hijack user sessions. Meanwhile, the Secure flag ensures that the cookie is only transmitted over a secure HTTPS connection, protecting against man-in-the-middle (MitM) attacks that could intercept and steal cookies transmitted over insecure HTTP connections. Here is an example:

CSP example

In this example, the Set-Cookie header sets a cookie named sessionId with a value of 12345. The HttpOnly flag is also set, which prevents client-side scripts from accessing the cookie. This helps to protect against cross-site scripting (XSS) attacks, which can be used to steal cookies and hijack user sessions. The Secure flag is also set, ensuring the cookie is only transmitted over a secure HTTPS connection.

3. Input validation and output encoding: Validate and sanitize user input to remove any malicious scripts and encode output to prevent script execution.

CSP example

In this example, we first validate the input using a regular expression to ensure that it only contains letters and spaces. If the input is invalid, we stop processing and display an error message. Next, we use the filter_var function with the FILTER_SANITIZE_STRING flag to sanitize the input and remove any potentially malicious scripts. Finally, when we display the name on the webpage using echo, we use the htmlentities function to encode the output and prevent any scripts from being executed.

Can your input have special chars like <, >, (, ) etc. For example “name” shouldn’t have these chars. Similarly, “phone” shouldn’t have them either. Filtering them on UI is a good user experience, but filter them on backend as well.

If you can have any kind of input - well, next step is going to help you.

4. Encode user input: Encode user input that is embedded within an HTML page. Ensure that the user-input is not directly present in the page. One way to achieve this is by using encoding techniques like base64 encoding. For instance, instead of directly using let name=${[user.name](<http://user.name/>)} in your code, use the following approach:

`let name = decodeBase64(”${user.base64encodedName}”)`

This technique ensures that the user-input is not directly part of your Document Object Model (DOM), thus reducing the risk of potential attacks such as cross-site scripting (XSS).

5. Do not embed user-input directly into your Document Object Model (DOM), especially when the user-input is being fetched from an API and displayed on the page. Instead, you should use techniques like escaping to modify the user-input before adding it to the DOM. For instance, convert characters like <, >, (, ), etc., to their corresponding HTML types like &lt, &gt, and so on.

6. If you are using popular front-end frameworks like Vue, React, or Angular, the framework itself can automatically perform the necessary "escaping" of user-input for you.

CSP example

Conclusion

If you have to take one message from this blog, we want it to be input validation. We cannot stress how important it is to use proper input validation techniques in your code to prevent XSS.

We at Akto are developing automated ways for devs to find XSS vulnerabilities in their code. Check out the product here and tell us what test you want to see related to XSS.

Follow us for more updates

Follow us for more updates

Follow us for more updates

Want to ask something?

Our community offers a network of support and resources. You can ask any question there and will get a reply in 24 hours.

Want to ask something?

Our community offers a network of support and resources. You can ask any question there and will get a reply in 24 hours.

Want to ask something?

Our community offers a network of support and resources. You can ask any question there and will get a reply in 24 hours.

Table of contents