black flat screen computer monitor
Sat Nov 26

XSS (Cross-Site Scripting) Explanation with Example

With the internet growing bigger every day, the understanding of cyber threats has become increasingly important. One of them is XSS or Cross-Site Scripting as it is the most common used by hackers.

Not only for web developers, it also applies to the internet users in general. In some cases, experienced hackers could even redirect you to a phishing website using XSS attacks, which would be fatal. For this reason, it is critical that you understand this issue.

What is XSS?

The XSS works by injecting scripts into the web. Because web pages are based on HTML, CSS, and JS, the script injected is usually based on these. It is a very common attack that can be done just by simply using any form on the web.

Keep in mind that the successful attack requires the attacker to be able to insert malicious code to the web page. As a minuscule mistake could lead to potential vulnerability, all variables involved in web pages need to go through validation and sanitization.

Some modern frameworks (like React and Angular) make it easier for the web developer to do the validation and sanitization. However, it won’t be enough as the security gaps may still exist. For this reason, HTML sanitization and output encoding may be beneficial in preventing XSS.

How does XSS work?

XSS was done by exploiting the vulnerability made by the developer. The vulnerabilities vary and could come from any contexts such as, HTML, HTML attribute, JavaScript and even CSS context. Let’s take a look at the most common one from the HTML attribute context.

While developing a web page, sometimes the user needs to know what they have been inserted in the input form. Take a look at the HTML code below.

<!DOCTYPE html>
<html>
   <head>
       <title>Example</title>
   </head>
   <body>
       <label for="name">Name:</label>
       <input id="name"></input>
       <input type="submit" value="Submit" onClick="result()">
       <div>Result:
         <div id="result"></div>
       </div>
       <script>
           function result() {
             const nameValue = document.getElementById("name").value;
             document.getElementById("result").innerHTML = nameValue;
           }
       </script>
   </body>
</html>

You can try it yourself by copy-pasting this code, and save it as index.html in your PC. And then you can run it using your preferred web browser and let me show you what’s going on.

This code will be interpreted as a very simple input that will return the same output as the input you inserted. If you are not familiar with HTML or JavaScript, the script tag above is where you use the JavaScript code directly on the web page.

As you can see, the function named **result** will be executed when the submit button is clicked. Inside the function, there are these two lines.

const nameValue = document.getElementById("name").value;
document.getElementById("result").innerHTML = nameValue;

The variable nameValue refers to the value of the element with****id=”name”. The next line replaces the innerHTML of the element with id=”result” with nameValue.

The innerHTML is just another way to insert text to the web page. If you insert your name or type anything and click submit, it works as intended. While it seems like nothing is wrong, it carries the potential security risk due to its ability to set HTML or XML markup.

What does it mean? Now, try to insert this HTML code directly to the input like this and press the submit button.

<h1>Hello</h1>

The result text should be bigger than it used to. The h1 tag is used to define heading in HTML. As you realize now, you can actually code in HTML from the user input. You might think, what if the attacker uses the script tag? How detrimental it could be. This is the reason why it doesn’t support script tags. Try this code on the input.

<script>alert(`Hacked!`)</script>

If it works, the web page will throw a popup with the word “Hacked!” in it. But it won’t work.

So, it is fully safe then. Well, not so much…

In fact, the script tag is not the only way to inject the JavaScript code. Another commonly used tag is img tag. In HTML, the img tag is used to insert an image. You may be wondering now, how an image could be used as a medium of hacking?

It is not really the image that gets the job done, but the tag itself. If you are familiar with HTML, the image tag requires the source path of the image to work properly. In HTML it could be written like this.

<img src="path-to-image"></img>

In XSS scripting, the src attribute is set to be intentionally wrong. Because of this, the page will throw an error. In case of such an event, the error can be handled by using onerror attribute. In normal circumstances, the developer usually uses this attribute to call a function when the error is triggered like this.

<img src="path-to-image" onerror=script-to-execute-if-error></img>

The attacker uses this to run a script in a web page. Let’s try to inject this script using this HTML code and submit.

<img src=1 onerror=alert(`Hacked!`)></img>

You can now see the pop up appear on the web page. Thus, you have successfully injected the script and this is how the XSS works.

Preventing XSS attack

Framework Security Protections

If you are a web developer, the use of a framework could be helpful for preventing you from this kind of vulnerability. Using a framework while doing web development is helpful as it steers the developer into good security practices.

In React for example, the innerHTML is replaced with dangerouslySetInnerHTML. This simple name makes the developer more aware of how risky it is to use. In reality, it doesn’t really give extra protection to XSS. Hence, another kind of protection is still needed.

Output Encoding

The above example is the classic one of how it was done. As stated before, the attack may come from any context.

Referring to the above example, we know that the problem is the innerHTML. Since it allows users to write HTML directly, it is better to change it. Now, edit the index.html using the text editor. Change it to innerText, save it, and run it. After that, try injecting the code using the image tag above.

Despite executing the code, it will throw the output as a text. Often, this is enough to prevent most XSS attacks. You can also change it to textContent as recommended by OWASP. textContent will automatically encode the HTML entity and therefore create a safe sink.

HTML Sanitization

If you are a web developer and you really need to use innerHTML (like getting the input from WYSIWYG editor), consider using the DOMPurify or any other HTML Sanitization method because output encoding will certainly break its functionality. HTML Sanitization works by removing the harmful HTML from a variable and returns the safe string ones. Because of this, patching this library regularly is always recommended.

Conclusion

There are many cyber threats targeting small or large websites, but XSS is especially prevalent. Despite its simplicity, the damage caused could be immense. Hence, it is very important to know, especially for web developers, as the occurrence could bring your entire career on the line.