Guard against DOM XSS security vulnerabilities in JavaScript

Have you heard of DOM XSS attacks? For those of you who haven’t.

A DOM XSS attack is when the hacker payload is executed to modify the DOM environment in the browser.

This causes the client code to run unexpectedly. Therefore, the vulnerability exists in the client code. Attackers make these attacks possible by taking advantage of instances where they can inject harmful payloads into your code. This is an injection attack.

DOM XSS injection can occur in a variety of ways. Some of them are as follows.

  • An element attribute setter that accepts the URL of the code to load, such as HTMLScriptElement. SRC
  • An element attribute setter that accepts the code to execute, such as HTMLScriptElement. Text
  • Functions that directly execute code, such as eval
  • Navigation to “javascript: “urls

Therefore, we need to take the necessary measures to avoid these problems at all costs.

Trusted type API to the rescue

The Google Chrome team announced an API called the Trusted Types API to control these DOM XSS security vulnerabilities. They are mainly due to the increasing number of DOM-based XSS vulnerabilities compared to server-side XSS vulnerabilities.

This is because DOM XSS is easy to introduce but harder to detect.

How do trusted type apis protect against DOM XSS attacks?

The trusted type API solves the XSS problem at its root. Let’s take a look.

The DOM API is insecure by default. Here are some examples.

eval('foo()');
Copy the code

It’s easy to inject malicious scripts or malicious HTML into these.

To avoid this, the trusted type API can set the HTTP response header for the Content Security Policy (CSP) to Content-security-Policy: trusted-types * to take advantage of only trusted types. This will enable developers to prevent dangerous injections and make them secure by default.

This can be enabled as follows.

Content-Security-Policy: trusted-types;
Copy the code

The trusted-types directive instructs the browser to create unspoofed, typed values that are passed to the DOM XSS sink in place of strings.

The main idea here is to pass objects to DOM sinks, not strings. DOM supports object passing.

elem.innerHTML = { toString: function() { return 'Hello World' }};
Copy the code

The Trusted Types API recommends passing typed objects instead of regular JS objects.

This causes the DOM sink to reject strings and accept only matching types.

Use trusted type apis in practice

If you are going to implement the Trusted Types API in your project, first, you need to find out where Trusted Types are being violated. This can be done very easily.

Check for trust type violations

Add the following HTTP response headers to the files you need to check for violations.

Content-Security-Policy-Report-Only: require-trusted-types-for 'script'; report-uri //mysite.com/cspViolations
Copy the code

Then, all the violations will be reported to the / / mysite.com/cspViolations. This does not interfere with any of your site’s functions.

Trusted type violation report

When a trusted type violation is detected, it is sent to a report using the report-URI configuration. For example, if you pass a string to innerHTML, a report similar to the following is generated.

{
Copy the code

This will help you determine which lines of code in which files are causing DOM XSS vulnerabilities on your site.

Resolving violations

There are several ways to eliminate trusted type violations. Let’s take a look at each of these methods.

1. Rewrite the offending code

For example, if you have a piece of code like el.innerhtml = ‘‘; , this can be rewritten as follows.

el.textContent = '';
Copy the code

This avoids assigning a string directly to innerHTML.

2. Use a library

A library like DOMPurify can be used to purify the HTML, and the HTML it returns is wrapped in a TrustedHTML object. This does not allow browsers to commit violations.

3. Create a trusted type policy

Instead of using a library or removing buggy code, you can create a trusted type object yourself. Trusted type policies enforce security rules on their input.

  • Step 1 – Create a policy
if (window.trustedTypes && trustedTypes.createPolicy) {
Copy the code

This rule omits the < character to prevent the creation of new HTML elements. CreatePolicy () returns a policy object that wraps the return value in the correct type; In this case, TrustedHTML.

  • Step 2 – Use the policy
const escaped = escapeHTMLPolicy.createHTML('<img src=x onerror=alert(1)>');
Copy the code
console.log(escaped instanceof TrustedHTML);  // true
Copy the code

If you cannot change the code (for example, when you purchase a third-party library from a CDN), you can use a default policy.

if (window.trustedTypes && trustedTypes.createPolicy) {
Copy the code

It’s a combination of policy and decontamination.

Once you’ve resolved all the violations, you can enforce trust types in your code. This is done in the following way.

Content-Security-Policy
Copy the code

You may notice that the -report-only suffix is not included here compared to our previous implementation.

In this section, we have only looked at resolving HTML violations. However, the Trusted Types API has the ability to detect violations and enforce rules in the following areas.

  • HTML
  • The script
  • The script URL
  • The script URL

Refer to this document for more information on these different types.

The benefits of enforcing trusted types

In the previous chapters, you’ve probably learned the benefits of implementing trusted types in your applications. I have listed them as a summary for your reference. These are the advanced benefits of using this API.

  • Reduce the attack surface of your site – applications are safe
  • Security verification at compile time and run time
  • Backward compatibility – The ability to use trusted types instead of strings
  • Complement other security solutions, such as CSP for server-side XSS

Before we wrap up, let’s also take a quick look at browser compatibility.

Browser compatibility

Unfortunately, Among the most common browsers, Firefox and Internet Explorer do not support Trusted Types. However, if you’re a die-hard Chrome user, you’re in luck.

Reference source

conclusion

DOM XSS attacks are now common and increasing rapidly. Detecting these attacks is much harder than we thought. Therefore, implementing a trusted type API is the best solution to protect our application from these attacks.

As we discussed earlier, this can be done easily and quickly. Here’s to building secure applications.

Thanks for reading!

Build and share independent components with bits

Bitbits is a super extensible tool that lets you create truly modular applications with components written, versioned, and maintained independently.

Use it to build modular applications and design systems, write and deliver microfronts, or simply share components between applications.

To learn more

  • JavaScript security issues and best practices
  • Enhance JavaScript security with content security policies
  • How to Hide secrets in strings — modern text hiding in JavaScript


Speaking of JavaScript DOM secure trusted type apis, Bits and Pieces, originally published on Medium, people continue the conversation by highlighting and responding to this story.