Guidelines

Injection - XSS

Cross-Site Scripting, also known as XSS, is another type of injection vulnerability that leads to the evaluation of an attacker-controlled script in another user's browser. XSS can also be considered an HTML/JavaScript injection vulnerability.

The impact of an XSS vulnerability depends heavily on the context in which the vulnerability exists. It ranges from being able to extract information from the page the script is run on and editing the page's state to perform actions as the victim on the page. 

Let’s look at the types of XSS you can encounter.

XSS Types

XSS can be split into a few buckets to help distinguish them. They’re categorized by how the payload is delivered and where the entry point is.

Payload delivery vector (Stored vs Reflected)

There are two ways that an attacker can deliver an XSS payload:

  • Stored XSS: Through user-controlled data stored in, for example, a database where the data is rendered to other users
  • Reflected XSS: Through a user-provided payload passed through the URL/query string that’s browsed to by a user

The critical distinction is that a Reflected XSS will usually depend on user interaction and only impact the user who opens the link with the malicious payload. However, a Stored XSS can be executed against one or more users by simply opening some pages that render the payload. 

Payload location (DOM vs Non-DOM)

The location that a payload is injected into determines whether you categorize the vulnerability as being a "DOM" vulnerability or not. This refers to the distinction between where the payload is rendered:

  • Non-DOM XSS: The payload is rendered inside HTML, whether that's inside a tag or an attribute
  • DOM XSS: The payload is rendered inside JavaScript, like a `<script>` tag, or an event handler such as `onclick=""` 

XSS - Defense primitives

In this section, will look at the principles of the primitives that underlie defending against XSS. Understanding the basics of this is essential, but in practice, you should be relying on your templating library for 99% of protection against XSS.

When you write templates that are rendered to markup or code running in a browser, the key to protecting against XSS is *encoding*. Encoding, in this context, means taking a sequence of characters and changing it into a format that gets processed in a specific way by the interpreter. 

But the type of encoding to use depends on the location or context for where the data will be used. 

  • Inside a tag, like `<div>User input here</div>`: **HTML Encoding**
  • Inside an attribute, like `<input placeholder="User input here"></input>`: **Attribute Encoding**
  • Inside Javascript, like `<script>x = "User input here";</script>`: **JavaScript Encoding**

Some frameworks will forego encoding as their primary means of defense and instead utilize sanitization to scrub a value from any content that could be dangerous. This is a much more complex process with many edge cases to consider. It's not recommended to implement your own sanitization routines.

Examples

Let’s take a look at some examples in various languages to see what it all looks like in action.

C# - Insecure: Razor

If an `IHtmlContent` object is prefixed with a `@`, the value is directly placed into the template without any encoding. 

<!--- UNSAFE: The htmlSnippet will get interpreted without any escaping --->
@Html.Raw(htmlSnippet)

C# - Secure: Razor

By default, any `string` prefixed with a `@` is HTML escaped in Razor templates. 

<!--- SAFE: The htmlSnippet will get HTML escaped --->
@htmlSnippet

Java - Secure: JSP

When using `c:out`, it XML escape by default (Which can be changed with the property `escapeXml`), which protects against XSS in a HTML context, but not in other contexts.

<div><c:out value="<%= author %>" /></div>

Java - Secure: (fnxml)

Similar to above, you can also directly call `fn:escapeXml`, which will XML escape the input given to it. This will also only protect in a HTML context.

<div>${fn:escapeXml(author)}</div>

Javascript - Insecure: Angular innerHtml

By specifying the `innerHTML` property, as the name suggests, you will be exposed to the risk of XSS due to disabling of output encoding.

<!--- UNSAFE: The htmlSnippet will get interpreted without any encoding --->
<p [innerHTML]="htmlSnippet"></p>

Javascript - Secure: Angular interpolated

Angular's interpolation of text using double curly braces (`{{` and `}}`) will HTML escape its output, protecting against XSS. 

<!--- SAFE: The htmlSnippet will get encoded and then interpreted --->
<p>{{htmlSnippet}}</p>

Javascript - Insecure: React dangerousInnerHtml

By specifying the `dangerouslySetInnerHTML` property, as the name suggests, you will be exposed to the risk of XSS due to disabling of output encoding.

<!--- UNSAFE: As the name suggests, the dangerouslySetInnerHTML attribute is dangerous as it does not escape the output --->
<div dangerouslySetInnerHTML={{ __html: htmlSnippet }} />;

Javascript - Secure: React interpolated

React's interpolation of text using curly braces (`{` and `}`) will HTML escape its output, protecting against XSS. 

<!--- SAFE: The htmlSnippet will get encoded and then interpreted --->
<div>{htmlSnippet}</div>

Python - Insecure: Django

If one uses the `safe` filter in a Django template, it will disable the automatic escaping of the output, and thus not protect against XSS.

<!--- UNSAFE: The htmlSnippet will not get HTML encoded --->
<div>{{ htmlSnippet | safe }}</div>

Python - Secure: Django

Django's interpolation of text using double curly braces (`{{` and `}}`) will HTML escape its output, protecting against XSS.

<!--- SAFE: The htmlSnippet will HTML encoded --->
<div>{{ name }}</div>