Внести вклад в Angular2

Я пытаюсь получить стороннее (потенциально небезопасное) содержимое HTML из моей базы данных и вставить его в мой документ HTML.

Как мне безопасно это сделать (Защита от XSS)?

В Angular1.x раньше был $sce для $sce ввода, как мне это сделать в Angular2? Насколько я понимаю, Angular2 автоматически очищает его по умолчанию, это правильно?

Как то так не получится

<div class="foo">
    {{someBoundValueWithSafeHTML}} // I want HTML from db here
</div>

Ответ 1

Чтобы вставить обычный HTML в ваше приложение angular2, вы можете использовать директиву [innerHtml].

<div [innerHtml]="htmlProperty"></div>

Это не сработает с HTML, который имеет свои собственные компоненты и директивы, по крайней мере, не так, как вы ожидаете.

Однако, если вы получаете небезопасное html-предупреждение, вам следует сначала довериться HTML прежде чем вводить его. Вы должны использовать DomSanitizer для такой вещи. Например, элемент <h3> считается безопасным. Элемент <input> не является.

export class AppComponent  {

    private _htmlProperty: string = '<input type="text" name="name">';

    public get htmlProperty() : SafeHtml {
       return this.sr.bypassSecurityTrustHtml(this._htmlProperty);
    }

    constructor(private sr: DomSanitizer){}
}

И пусть ваш шаблон останется таким же:

<div [innerHtml]="htmlProperty"></div>

Немного хедз-ап, хотя:

ВНИМАНИЕ: вызов этого метода с ненадежными пользовательскими данными подвергает ваше приложение угрозам безопасности XSS!

Если вы планируете использовать эту технику больше, вы можете попробовать написать @Pipe для выполнения этой задачи.

import { Pipe, PipeTransform } from '@angular/core';
import { DomSanitizer, SafeHtml } from '@angular/platform-browser';

@Pipe({
    name: 'trustHtml'
})
export class TrustHtmlPipe implements PipeTransform  {    
   constructor(readonly sr: DomSanitizer){}  

   transform(html: string) : SafeHtml {
      return this.sr.bypassSecurityTrustHtml(html); 
   } 
} 

Если у вас есть такой канал, ваш AppComponent изменится на этот. Не забудьте добавить канал в массив объявлений вашего NgModule:

@Component({
   selector: 'app',
   template: '<div [innerHtml]="htmlProperty | trustHtml"></div>'
})
export class AppComponent{

    public htmlProperty: string = '<input type="text" name="name">';

} 

Или вы можете написать @Directive чтобы сделать то же самое:

@Directive({
   selector: '[trustHtml]'
})
export class SanitizeHtmlDirective {

    @Input()
    public set trustHtml(trustHtml: string) {
      if (this._trustHtml !== trustHtml) {
        this._trustHtml = trustHtml;
        this.innerHtml = this.sr.bypassSecurityTrustHtml(this.trustHtml);
      }
    }

    @HostBinding('innerHtml')
    innerHtml?: SafeHtml;

    private _trustHtml: string;

    constructor(readonlysr: DomSanitizer){}
}

Если у вас есть такая директива, ваш AppComponent изменится на эту. Не забудьте добавить директиву в ваш массив объявлений вашего NgModule:

@Component({
   selector: 'app',
   template: '<div [trustHtml]="htmlProperty"></div>'
})
export class AppComponent{

    public htmlProperty: string = '<input type="text" name="name">';

}