DomSanitizer w Angular

Serwis, który dba o to aby nasza aplikacja była odporna na ataki XSS usuwając niebezpieczny kod (ang. sanitizing).

Pisząc aplikację w Angularze często korzystamy z dynamicznego podstawiania wartości w takich miejscach jak link lub wykorzystując atrybut innerHtml. Miejsca te mogą być potencjalnymi miejsca ataku. DomSanitizer pomaga nam w utrzymaniu bezpiecznej aplikacji.

Atak XSS

Na początku wyjaśnijmy sobie czym jest atak XSS (skrót od ang. Cross-site scripting). Polega na przesłaniu do aplikacji złośliwego kodu (najczęściej Javascript), który wykona się po w przeglądarce innego użytkownika. Atakujący może to zrobić za pomocą przesłania odpowiednio przygotowanego komentarza, którego próba odczytu w przeglądarce innego użytkownika może spowodować szkody.

Jak działa DomSanitizer

Wyobraźmy sobie sytuację, w której dajemy użytkownikowi możliwość umieszczania linków do swojego portfolio lub profili w social media. Link może być odpowiednio przygotowany tak aby wykonywał kod Javascript, który wykona się po stronie tego kto kliknie w link. Aby temu zapobiec Angular podczas umieszczania dynamicznych wartości w [href] doda frazę unsafe przy niebezpiecznym kodzie Javascript. Po kliknięciu w link nie zostanie uruchomiony żaden kod Javascript.

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

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html'
})
export class AppComponent {
  public link = `javascript:alert('test')`;
}
<a [href]="link">Link</a>

Wynikowym kodem, który ukaże się w przeglądarce jest:

<a href="unsafe:javascript:alert('test')">Link</a>

Możemy ten proces wywołać sami wywołując metodę sanitize z serwisu DomSanitizer.

import { Component, SecurityContext } from '@angular/core';
import { DomSanitizer } from '@angular/platform-browser';

@Component({
  selector: 'app-root',
  template: `<a [href]="link">Link</a>`,
})
export class AppComponent {
  public link: string;

  constructor(private sanitizer: DomSanitizer) {
    this.link = this.sanitizer.sanitize(SecurityContext.URL, 'javascript:alert(1)');
  }
}

Zaufany kod

Są sytuacje, w których chcemy użyć potencjalnie niebezpiecznego kodu w naszej aplikacji. Żeby to zrobić możemy skorzystać z serwisu DomSanitizer.

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

constructor(private sanitizer: DomSanitizer) {
}

Serwis dostarcza kilku funkcji dla różnych kontekstów wywołań niebezpiecznego kodu.

Oznacz HTML jako bezpieczny

Użyj DomSanitizer.bypassSecurityTrustHtml, aby oznaczyć HTML jako bezpieczny do użycia.

import { Component } from '@angular/core';
import { DomSanitizer, SafeValue } from '@angular/platform-browser';

@Component({
  selector: 'app-root',
  template: `<div [innerHTML]="html"></div>`
})
export class AppComponent {
  public html: SafeValue;

  constructor(private sanitizer: DomSanitizer) {
    this.html = this.sanitizer.bypassSecurityTrustHtml(`<svg width="100" height="100"><circle cx="50" cy="50" r="40" stroke="green" stroke-width="4" fill="yellow" /></svg>`);
  }
}

Oznacz styl jako bezpieczny

Użyj DomSanitizer.bypassSecurityTrustStyle, aby oznaczyć styl jako bezpieczny do użycia.

import { Component } from '@angular/core';
import { DomSanitizer, SafeStyle } from '@angular/platform-browser';

@Component({
  selector: 'app-root',
  template: `<div [style]="style"></div>`,
})
export class AppComponent {
  public style: SafeStyle;

  constructor(private sanitizer: DomSanitizer) {
    this.style = this.sanitizer.bypassSecurityTrustStyle('color: white; display: block;');
  }
}

Oznacz kod Javascript jako bezpieczny

Użyj DomSanitizer.bypassSecurityTrustScript, aby oznaczyć kod Javascript jako bezpieczny do użycia.

import { Component } from '@angular/core';
import { DomSanitizer, SafeScript } from '@angular/platform-browser';

@Component({
  selector: 'app-root',
  template: ``,
})
export class AppComponent {
  public script: SafeScript;

  constructor(private sanitizer: DomSanitizer) {
    this.script = this.sanitizer.bypassSecurityTrustScript('alert(1)');
  }
}

Oznacz URL jako bezpieczny

Użyj DomSanitizer.bypassSecurityTrustUrl, aby oznaczyć url jako bezpieczny do użycia.

import { Component } from '@angular/core';
import { DomSanitizer, SafeUrl } from '@angular/platform-browser';

@Component({
  selector: 'app-root',
  template: `<a [href]="url">Safe url</a>`,
})
export class AppComponent {
  public url: SafeUrl;

  constructor(private sanitizer: DomSanitizer) {
    this.url = this.sanitizer.bypassSecurityTrustUrl("https://www.youtube.com/embed/dQw4w9WgXcQ");
  }
}

Oznacz źródło jako bezpieczne

Użyj DomSanitizer.bypassSecurityTrustResourceUrl, aby oznaczyć url, który będzie źródłem np. dla iframe jako bezpieczny do użycia.

import { Component } from '@angular/core';
import { DomSanitizer, SafeResourceUrl } from '@angular/platform-browser';

@Component({
  selector: 'app-root',
  template: `<iframe [src]="iframe"></iframe>`,
})
export class AppComponent {
  public iframe: SafeResourceUrl;

  constructor(private sanitizer: DomSanitizer) {
    this.iframe = this.sanitizer.bypassSecurityTrustResourceUrl("https://www.youtube.com/embed/dQw4w9WgXcQ");
  }
}

Podsumowanie

Nawet w większej aplikacji użycie serwisu DomSanitizer jest rzadkie, ponieważ większość operacji zwiększających bezpieczeństwo naszej aplikacji jest robione przez Angulara w tle. Częściej użyjemy go w przypadku chęci ominięcia tych operacji – używając metod z przedrostkiem bypass.

Oznaczajmy kod jako bezpieczny z rozwagą, a w momentach w których nie jesteśmy pewni treści używajmy metody sanitize aby możliwie jak najlepiej zabezpieczyć naszą aplikację.

Udostępnij
Default image
Wojciech Szućko
Jestem Angular Developerem. Przedstawiam techniki i technologie, które wykorzystuje w codziennej pracy z web aplikacjami. Tworzyłem projekty między innymi dla Bank Pekao S.A., AlphaTauri czy Playmobil.