Angular 7 DOM 清理混合内容

Angular 7 DOM sanitizing of mixed content

我需要做一个像codepen.io这样的私人服务。用户必须有可能创建包含脚本、样式、内联脚本和内联样式的混合内容(是的,具有很多漏洞的 XSS 不安全内容)。

Service screenshot

我的服务有一个 iframe 和 Monaco 代码编辑器。 我应该如何在没有 Angular XSS 防御和清理的情况下将用户生成的 HTML、样式和脚本插入 iframe?

Angular7 怎么办?

也许存在一种手动将用户生成的内容标记为已清理的方法?

重要的代码片段。

view.component.html:

<iframe id="view" [srcdoc]="resultPage | safe: 'html'"></iframe>

view.component.ts:

@Component({
  selector: 'app-view',
  templateUrl: './view.component.html',
  styleUrls: ['./view.component.scss']
})
export class ViewComponent implements OnInit {

  resultPage = '';

  _task: Task;
  set task(value: Task) {
    this._task = value;
    if (value) {
      this.refreshPage();
    }
  }
  get task() {
    return this._task;
  }

  constructor(private store: Store<RootStoreState.State>) { }

  ngOnInit() {
    this.store.pipe(select(selectSelectedTask))
      .subscribe((task) => {
        this.task = task;
      });
  }

  refreshPage() {
    if (!this.task) {return; }
    const htmlFile = this.task.files.find((item) => item.language === 'html')
    const cssFile = this.task.files.find((item) => item.language === 'css')
    const jsFile = this.task.files.find((item) => item.language === 'js')
    let html = htmlFile ? htmlFile.content : null;
    if (!html) {
      return;
    }
    let css = cssFile ? cssFile.content : null;
    let js = jsFile ? jsFile.content : null;
    html = this.insertCss(html, css);
    this.resultPage = html;
  }

  insertCss(html: string, css: string): string {
    const cssPlaceholder = `<style>${css}</style>`;
    const closedHead = html.indexOf('</head>');
    if (closedHead > -1) {
      html.replace('</head>', cssPlaceholder + '</head>');
      console.log(1, html);
      return html;
    }
    const openedBody = html.indexOf('<body>');
    if (openedBody > -1) {
      html.replace('<body>', '<body>' + cssPlaceholder);
      console.log(2, html);
      return html;
    }
    html += css;
    console.log(3, html);
    return html;
  }

}

尝试使用 DomSanitizer

Calling any of the bypassSecurityTrust... APIs disables Angular's built-in sanitization for the value passed in

我遇到了类似的问题。我找到了如下解决方法。

我没有使用 angular 提供的 srcdoc directive,而是创建了一个自定义指令来设置 srcdoc attribute of iframe element

这是代码

srcdoc.directive.ts

import { Directive, Input, ElementRef, Renderer2, OnChanges, SimpleChanges } from "@angular/core";

@Directive({
  selector : '[app-srcdoc]'
})
export class SrcdocDirective implements OnChanges{
  // add data binding to directive itself
  @Input("app-srcdoc") source:string;
 
  constructor(private elementRef:ElementRef,private renderer:Renderer2) {}

  // update the srcdoc attribute whenever the binding changes
  ngOnChanges(changes: SimpleChanges): void {
    this.renderer.setAttribute(this.elementRef.nativeElement,"srcdoc",changes.source.currentValue);
  }

}

按如下方式使用您的组件 html

<iframe id="output" [app-srcdoc]="iframeContent" ></iframe>