在Angular中使用bypassSecurityTrustStyle清理脚本

时间:2019-06-03 11:09:33

标签: angular

我需要从字符串中剥离所有script标签,但要保留style

如果我清理此字符串的style

getSanitized(s: string) {
    const safeStyle: any = this.sanitizer.bypassSecurityTrustStyle(s);
    return safeStyle.changingThisBreaksApplicationSecurity;
}

const s = '<span style="font-size:18px;color:blue">This is a title</span>';
console.log(this.getSanitized(s));

我得到相同的字符串,因为它只包含样式,而且看起来工作正常。

但是如果字符串包含script,例如

const s = `<script>alert(1);</script>  
           <span onclick="javascript:alert(2);" 
                 style="font-size:18px;color:blue">This is a title</span>';`
console.log(this.getSanitized(s));

不会从字符串中消除script标记和onclick属性。如果我在style级进行消毒,为什么不能消除它?

1 个答案:

答案 0 :(得分:1)

Angular Sanitizer不会修改传递的HTML内容。它不会从中提取任何内容。您需要手动执行此操作。例如,您可以解析传递的HTML内容,从中删除不必要的代码,然后再次将其序列化为字符串。

我知道htmlparser2软件包可以从HTML构建AST。您可以使用它来解析HTML。要将AST序列化为字符串,可以使用dom-serializer包。

因此,使用这些软件包或类似软件包,您的getSanitized函数逻辑可能会遵循:

async getSanitized(s: string): Promise<string> {
  // 1. make an AST from HTML in a string format
  const dom = await this.getAST(s);
  // 2. remove unwanted nodes from the AST
  const filteredDOM = this.filterJS(dom);
  // 3. serialize the AST back to a string
  const result: string = serializer(filteredDOM);
  return result;
}

getAST函数仅使用htmlparser2 API从字符串中获取AST:

getAST(s: string): Promise<DomElement[]> {
  return new Promise((res, rej) => {
    const parser = new Parser(
      new DomHandler((err, dom) => {
        if (err) {
          rej(err);
        } else {
          res(dom);
        }
      })
    );
    parser.write(s);
    parser.end();
  });
}

filterJS函数可删除不必要的节点。 AST htmlparser2生成了一个在线可视化程序:https://astexplorer.net/。您可以轻松查看需要使用哪些条件来过滤节点。 filterJS函数可以实现为:

filterJS(dom: DomElement[]): DomElement[] {
  return dom.reduce((acc, node) => {
    if (node.type === 'tag') {
      node.attribs = this.filterAttribs(node.attribs);
      node.children = this.filterJS(node.children);
    }
    if (node.type !== 'script') {
      acc.push(node);
    }
    return acc;
  }, []);
}

简而言之,它将删除script标签并调用filterAttribs函数以从事件处理程序中删除JavaScript。 filterAttribs函数可以是:

filterAttribs(attribs: { [s: string]: string }) {
  return Object.entries(attribs).reduce((acc, [key, value]) => {
    if (!key.startsWith('on')) {
      acc[key] = value;
    }
    return acc;
  }, {});
}

基本上,它会删除从“ on”开始的属性,即事件处理程序。

serializer函数是对dom-serializer库的调用。

不要忘记导入htmlparser2dom-serializer

import { DomHandler, Parser, DomElement } from 'htmlparser2';
import serializer from 'dom-serializer';

为了获得更好的TypeScript体验,htmlparser2库使用@types/htmlparser2包提供了类型定义。

您可以在https://stackblitz.com/edit/angular-busvys上找到有效的示例。