How to avoid XSS attacks using DomSanitizer service in AngularJS

AngularJS is a JavaScript based front end web framework for developing single page applications.It is a wonderful framework. It provides good security but you cannot rule out the possibility of getting attacked. We will see how to protect our AngularJS applications from XSS attacks. In our example we assume the data received from a call to an API contains a link URL and you want to render a corresponding HTML element. It is normally done using property binding.

import { Component } from "@angular/core";

@Component({

  selector: "my-app",

  templateUrl: "./app.component.html",

  styleUrls: ["./app.component.css"]

})

export class AppComponent {

  public basicUrl = 'javascript:alert("HACKED!!!")';

}

<div class="mb-5">

  <p>Binding link url - sanitized by Angular</p>

  <a [href]="basicUrl" class="btn btn-success">Click</a>

</div>


Here the value bound to the href attribute is an example for XSS attack. Here is when Angular steps in and sanitizes it automatically. There is a DomSanitizer service method that allows you to tell Angular that you are responsible for providing safe values. You can do it by using the bypassSecurityTrustURL method in DomSanitizer service. 

import { AfterViewInit, Component } from "@angular/core";

import { DomSanitizer, SafeUrl } from "@angular/platform-browser";


@Component({

  selector: "my-app",

  templateUrl: "./app.component.html",

  styleUrls: ["./app.component.css"]

})

export class AppComponent implements AfterViewInit {

  public basicUrl = 'javascript:alert("HACKED!!!")';

  public theoreticallySafeUrl: SafeUrl;

  ...

  constructor(private sanitizer: DomSanitizer) {}

  ngAfterViewInit(): void {

    setTheoreticallySafeUrl();

  }

  ...

  private setTheoreticallySafeUrl(): void {

    this.theoreticallySafeUrl = this.sanitizer.bypassSecurityTrustUrl(

      this.basicUrl

    );

  }

}


The problem with this method is that it returns a SafeURL instance which tells the theoreticallySafeURL contains a sanitized value. It only implies that property has been marked as sanitized by a developer and Angular does not need to step in. If you didn’t take any actions to sanitize it there would be an XSS attack.

<div class="mb-5">

  <p>Binding link url - SafeUrl is not sanitized by Angular</p>

  <a class="btn" [href]="theoreticallySafeUrl">Click</a>

</div>

DOM manipulation using the native API is highly discouraged in Angular applications but it's effective. The problem is that if you do this Angular will not sanitize the values. 

If you want to use DOM anyway you can make use of Renderer service. Using Renderer service brings some advantages but it will not include sanitization.

import {

  AfterViewInit,

  Component,

  ElementRef,

  Renderer2

} from "@angular/core";


@Component({

  selector: "my-app",

  templateUrl: "./app.component.html",

  styleUrls: ["./app.component.css"]

})

export class AppComponent implements AfterViewInit {

  public basicUrl = 'javascript:alert("HACKED!!!")';

  ...

  private get host(): HTMLElement {

    return this.el.nativeElement;

  }


  constructor(

    private renderer: Renderer2,

    private el: ElementRef

  ) {}


  ngAfterViewInit(): void {

    setUrlUsingRenderer();

  }

  ...

  private setUrlUsingRenderer(): void {

    const link = this.getLink(".link-renderer");

    this.renderer.setAttribute(link, "href", this.basicUrl);

  }

  private getLink(selector: string): HTMLAnchorElement {

    return this.host.querySelector(selector);

  }

}

So these are three cases of avoiding XSS attacks. Since these do not provide sanitization you can use DomSanitizer service and sanitize method.

import { Component, SecurityContext } from "@angular/core";

import { DomSanitizer } from "@angular/platform-browser";


@Component({

  selector: "my-app",

  templateUrl: "./app.component.html",

  styleUrls: ["./app.component.css"]

})

export class AppComponent {

  public basicUrl = this.sanitizer.sanitize(SecurityContext.URL, 'javascript:alert("HACKED!!!")');

  ...

  constructor(private sanitizer: DomSanitizer) {}

  ...

 }

Now the URL is sanitized and it is safe to use it when manipulating the DOM using Renderer or native API.