Angular has your back when it comes to XSS

profile
Tim Deschryver
timdeschryver.dev

Cross-Site Scripting (XSS) link

Cross-Site Scripting (XSS) is a security vulnerability that allows an attacker to inject malicious code into a web application. For years, it's been on the OWASP Top 10 list of the most critical security risks to web applications, in the latest version (published in 2021) it's ranked 3rd.

If this is the first time you've heard about XSS, I would say that this is normal because Angular does a great job of protecting us from this threat behind the scenes. Nevertheless, I think it's important to understand what it is, and how Angular protects us from it.

A simple example to illustrate the concept of XSS is an inserted script tag that executes malicious code. This can be easy to detect. Attackers have become more sophisticated with their manners, for example using an image tag with a src attribute that points to an invalid location. When the browser tries to load the image, it will execute the JavaScript code in the onerror attribute.

Another example is an anchor tag with a href attribute that executes JavaScript code.

The above examples simply show an alert, but an attacker could do much worse.

Note

These examples are just a few of the many ways an attacker can exploit a web application. For more exploits, you can take a look at the Vulnerability Payload List. Some of these payloads are really creative and scary.

Angular's built-in protection link

So how does Angular protect us from these attacks? The answer is simple: Angular is very skeptical and treats all values as untrusted by default.

When a value is used within the DOM template either using interpolation or property binding, Angular sanitizes and escapes untrusted values.

Default JavaScript behavior link

Before we go over some examples of how Angular handles this, let's first take a look at the default JavaScript behavior. Consider the following malicious input:

To render this input in the DOM, we can use the following JavaScript code:

When this gets rendered to the DOM, the following will happen:

The default behavior without built-in protection

Using interpolation link

Now compare the default behavior with Angular's behavior.

Using Angular's interpolation, we can render the same malicious input:

When this gets rendered to the DOM, the following will happen:

Resulting in the following output. Because the input is rendered as plain text, the JavaScript code is not interpreted as code by the browser and thus not executed when the link is clicked.

The input is rendered as plain text

Using property binding link

Angular also allows us to render the input using property binding:

When this gets rendered to the DOM, the following will happen:

Resulting in the following output.

The input is rendered as HTML, but it's sanitized

When Angular detects that a value is untrusted, it will sanitize the value before rendering it to the DOM. If this occurs, a warning will be logged to the console (in dev mode).

Angular logs when it sanitizes a value

DomSanitizer link

If for some reason you need to manually sanitize a value, you can use the DomSanitizer service. This can be used to fix the preceding example Default JavaScript behavior.

Instead of directly setting the innerHTML of an element, you can use the DomSanitizer service to sanitize the value before rendering it to the DOM.

This has the same effect as using property binding in Angular.

The technicals on how Angular protects us link

So how does Angular protect us from these attacks? Using the code in @core/sanitization Angular analyzes the input string and sanitizes and escapes untrusted values. Without going into too much detail, you can take a look at the source code. Here we can see that Angular keeps an allowlist of safe values and escapes all other values.

Tip

Alisa Duncan has a great webinar on this topic, see Staying Safe and Secure with Angular for the recording of it during ng-conf.

Feel free to update this blog post on GitHub, thanks in advance!

Join My Newsletter (WIP)

Join my weekly newsletter to receive my latest blog posts and bits, directly in your inbox.

Support me

I appreciate it if you would support me if have you enjoyed this post and found it useful, thank you in advance.

Buy Me a Coffee at ko-fi.com PayPal logo

Share this post

Twitter LinkedIn