Angular has your back when it comes to XSS
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.
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 HTML entities (
strong
,a
,span
) are rendered - the JavaScript code in the
href
attribute will be executed when the link is clicked - the style attribute is rendered
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:
- the input is escaped and is rendered as plain text
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.
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:
- the HTML entities (
strong
,a
,span
) are rendered - the JavaScript code is marked as unsafe and is not executed on click (note that links within the
href
attribute are not sanitized and will redirect the user to that location) - the style attribute is stripped
Resulting in the following output.
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).
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.
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.