Learning Objectives

After completing this unit, you'll be able to:
  • Explain what a cross-site scripting vulnerability is.
  • Define the three types of XSS attacks.
  • List three impacts of XSS against internal users.

What Is Cross-Site Scripting?

Rather than the static unchanging pages of the past, current web applications are dynamic and constantly updated based on actions taken by the end user. A simple click of a button can create popup windows, submit forms, or even play music. While this increase in functionality has made applications more usable, it has its downside: security vulnerabilities. In fact, one of the most common web application vulnerabilities, cross-site scripting (XSS), enables an attacker to take advantage of expanded functionality to exploit other users and the underlying system.

XSS is an injection vulnerability that occurs when an attacker can insert unauthorized JavaScript, VBScript, HTML, or other active content into a web page. When other users view the page, the malicious code executes and affects or attacks the user. For example, a malicious script can hijack the user’s session, submit unauthorized transactions as the user, steal confidential information, or simply deface the page.

As the developer and therefore defender of the Kingdom Management app, you need to spot issues and fortify your code to prevent XSS. Prevention is vital to protect your users and to get through security reviews to get listed on the AppExchange.

How Does an XSS Attack Work?

In the simplest form, XSS attacks occur when user-supplied input is reflected in the HTML of a web page. Due to poor separation between code context and user data, the user input is executed as code.

In Kingdom Management, you have implemented a page to create a scroll that can be used in the Kingdom to post announcements. As you audit your application for security vulnerabilities, you wonder if this component is vulnerable to XSS. So let’s test it out!

  1. Log in to the Kingdom Management developer org and select the Cross-Site Scripting (XSS) app.
  2. Click the XSS Basics - Demo tab.
  3. In the message text field, enter a basic message like: Hear ye, hear ye, come one, come all!
  4. Click the Create Scroll button.
  5. The page should refresh, and you should see the text you entered in the previous step.
  6. Right click on the page and select View source
  7. If you search in the raw HTML for your message, you should see HTML like: <i>Hear ye, hear ye, come one, come all!</i>

    But what if you tried something different? XSS vulnerabilities result when user input is executed as code. So what happens if we enter code into this message box? Will it execute?

  8. Back in the Kingdom Management developer org, enter the following before clicking Create Scroll: <u>Testing for underline</u>

    Did the underline effect occur? Yes! It appears that text we enter into the input box is being interpreted as code! Now what happens if we try something a lot more complicated?

  9. Enter the following in the message text field: <img src=x onerror="alert(\'I said, HEAR YE, HEAR YE, COME ONE, COME ALL!!\');"></img>
  10. Click Create Scroll. You see a little window pop up.
    XSS proof of concept popup

Let’s take a closer look at this page’s source code to see exactly where this is happening.

Apex:

if(apexpages.currentpage().getparameters().get('text')!=null && apexpages.currentpage().getparameters().get('text')!='')
basicText=apexpages.currentpage().getparameters().get('text');
outputText = basicText.replace('\r\n','<br/>');

Visualforce:

<apex:page controller="XSS_Basics_Demo" sidebar="false" tabStyle="XSS_Basics_Demo__tab">
    [...]
    <script>
        document.getElementById('{!$Component.textOutput}').innerHTML = 
            '<div style="background-image: url({!$Resource.scroll});
            background-size:100%; height: 320px; width: 400px;"><b><font size="4" style="font-family: \'Alex Brush\', cursive; padding-top: 10px; padding-left: 50px; padding-right: 50px; display: inline-block;" ><i>{!outputText}<i></font></p></div>';
    </script>

But why did this happen? The poor separation between code (the HTML) and user data (the message) means the injected JavaScript is treated as HTML/JavaScript code and the browser executes it. Looking closer, the above code can be simplified to the following key lines:

basicText=apexpages.currentpage().getparameters().get('text');
outputText = basicText.replace('\r\n','<br/>');

The variable outputText is generated from the URL parameter text, and thus is under the user's control.

document.getElementById('{!$Component.textOutput}').innerHTML = '<p>{!outputText}</p>';

In Visualforce, the outputText merge field is applied to innerHTML as code. This means that user input is directly translated to code, providing the user with the ability to write arbitrary code to the page via a URL parameter. The user input could be as simple as “bob” or it could be an <img> tag, vastly modifying the purpose of the outputText merge field.

Types of XSS Attacks

The code we walked through above is an example of one type of XSS called a stored XSS attack. There are actually three different types that all vary in the way that the malicious payload is injected into and processed by the application.

  • Stored XSS — Stored XSS occurs when a malicious input is permanently stored on a server and reflected back to the user in a vulnerable web application. This often occurs when a malicious value can be stored in a database and retrieved, such as with a message board post or data in a user profile.
  • Reflected XSS — Reflected XSS occurs when malicious input is sent to a server and reflected back to the user on the response page.

    For a reflected XSS attack to succeed, the attacker needs to convince the user to click a link that has the malicious input in it, like: https://vulnerablesite.com?param=<script>document.cookie()</script>. While this may not fool your more savvy users, even the most experienced white knight can be tricked by the use of services like link shorteners, which obfuscate the underlying URL.

  • DOM-based XSS — DOM-based XSS occurs when an attack payload is executed as a result of modifying the web page’s document object model (DOM) in the victim user’s browser. The web page itself is not changed, but its client-side code executes in a malicious way because of these DOM changes. In this case, the web application’s server or database is never involved. This is an important distinction, because many security products can’t catch this kind of attack if the malicious input doesn’t reach the server.

Impact of XSS

While the XSS attack that we demonstrated earlier was fairly benign, XSS can have wide-ranging impact. It can be as simple as a user playing a joke on another user—to make things pop up or change colors, or to bounce images around the web page—but it can also be used for much more nefarious attacks.

Let’s consider how an external attacker would leverage this attack. Some attackers are financially motivated and would look to compromise credit card or bank account information. Some attackers are politically or socially motivated and may look to deface a page, impacting a company's reputation as a form of protest. Or even attackers may be hired by a competitor to target user accounts with a goal of accessing your data as a form of corporate espionage. Here are some other common XSS attack types.

  • Arbitrary requests — An attacker can use XSS to send requests that appear to be from the victim to the web server.
  • Malware download — XSS can prompt the user to download malware. Since the prompt looks like a legitimate request from the site, the user may be more likely to trust the request and actually install the malware.
  • Log keystrokes — The attacker can monitor keyboard entries, possibly finding usernames and passwords to access accounts at later dates.

Common XSS Mitigations

Now that you’ve seen the dangers that XSS poses to your users, we’ll arm you with weapons that you can use in your application to protect against these attacks. As we mentioned previously, XSS is caused by weak separation between code context (the actual underlying application) and user data (any information submitted by the user). An attacker can submit malicious code and convince the application to execute it. To fortify your defenses, you will strengthen the barrier between these two components.

There are two basic techniques to accomplish this: input filtering and output encoding.

Input Filtering

Input filtering works on the idea that malicious attacks are best caught at the point of user input. If the user inputs <b>duck</b> and the page strips or blocks the code, then no unauthorized code runs. There are two types of input filtering.

  • Blacklisting — Specific “bad” characters or combinations of characters are banned, meaning they can’t be entered or stored. The developer creates a list of known bad characters (such as HTML or script tags) and throws an error if any bad characters are in the input.
  • Whitelisting — Only characters or words from a known list of entries are permitted, preventing malicious input. For example, if the user enters anything besides numbers in a phone number field, the application throws an error.

Of the two input filtering methods, whitelisting is considered the more secure approach. For whitelisting to be effective, the developer only needs to know the expected input values, while blacklisting requires the developer to maintain a list of all potential malicious entries, often an impossible task.

Output Encoding

While input filtering techniques work by preventing malicious data from entering the system, output encoding techniques take an opposite approach: They prevent malicious payloads already in the system from executing. In fact, output encoding is often considered more necessary than input encoding because it doesn’t rely on any upstream or downstream protections, and it can’t be bypassed by alternative input pathways.

In output encoding, a server takes all characters that are meaningful in a specific context (HTML, JavaScript, URL) and replaces them with characters that represent its text version. For example, consider the "<” character. In HTML, this character signifies the start of a tag (like <b> for bold), but in mathematical functions the character means greater than.

So how does your browser tell the difference? Encoding! Encoding enables a meaningful character to be included in a block of text via a controlled substitution that removes the meaning. In the case of the "<" character, you can replace it with the characters "&lt;" and your browser will understand that you want the text version of "<", not the HTML version.

As a developer, you can use this same concept to mitigate XSS, because characters that can act as code aren’t represented in their meaningful version inside a block of code. Only the characters’ text equivalents appear.

Share Time Estimate