Open
Description
如何让字符串的dom元素渲染到页面上
让字符串的dom元素渲染到页面上而不是以字符串的形式显示出来。
假设有这样一个字符串:
domStr = "<div style='color: red'>我是一只开心的div</div>"
1. 自定义一个管道
/**
* dom元素渲染管道
*/
import { Pipe, PipeTransform } from "@angular/core";
import {
DomSanitizer,
SafeHtml,
SafeStyle,
SafeScript,
SafeUrl,
SafeResourceUrl
} from "@angular/platform-browser";
@Pipe({
name: "safe"
})
export class SafePipe implements PipeTransform {
constructor(protected sanitizer: DomSanitizer) {}
public transform(
value: any,
type: string
): SafeHtml | SafeStyle | SafeScript | SafeUrl | SafeResourceUrl {
switch (type) {
case "html":
return this.sanitizer.bypassSecurityTrustHtml(value);
case "style":
return this.sanitizer.bypassSecurityTrustStyle(value);
case "script":
return this.sanitizer.bypassSecurityTrustScript(value);
case "url":
return this.sanitizer.bypassSecurityTrustUrl(value);
case "resourceUrl":
return this.sanitizer.bypassSecurityTrustResourceUrl(value);
default:
throw new Error(`Invalid safe type specified: ${type}`);
}
}
}
2. 用法
直接使用管道转换
<span [outerHTML]="domStr | safe: 'html'"> </span>
DomSanitizer 解析
- Angular常规Web应用程序的安全原则
- 避免直接使用dom api
- 启用内容安全策略(CSP)并配置web服务器以返回适当的CSP HTTP头
- 使用离线模板编译器。
- 使用服务器端XSS保护。
- 使用DOM过滤器。
- 防止CSRF或XSRF攻击。
例子
export const BROWSER_SANITIZATION_PROVIDERS: Array<any> = [
{provide: Sanitizer, useExisting: DomSanitizer},
{provide: DomSanitizer, useClass: DomSanitizerImpl},
];
@NgModule({
providers: [
BROWSER_SANITIZATION_PROVIDERS
...
],
exports: [CommonModule, ApplicationModule]
})
export class BrowserModule {}
- DOM 过滤器:用于过滤值中不可信的部分, 源码:
export enum SecurityContext { NONE, HTML, STYLE, SCRIPT, URL, RESOURCE_URL }
export abstract class DomSanitizer implements Sanitizer {
abstract sanitize(context: SecurityContext, value: SafeValue|string|null): string|null;
abstract bypassSecurityTrustHtml(value: string): SafeHtml;
abstract bypassSecurityTrustStyle(value: string): SafeStyle;
abstract bypassSecurityTrustScript(value: string): SafeScript;
abstract bypassSecurityTrustUrl(value: string): SafeUrl;
abstract bypassSecurityTrustResourceUrl(value: string): SafeResourceUrl;
}
sanitize(ctx: SecurityContext, value: SafeValue|string|null): string|null {
if (value == null) return null;
switch (ctx) {
case SecurityContext.NONE:
return value as string;
case SecurityContext.HTML:
if (value instanceof SafeHtmlImpl) return value.changingThisBreaksApplicationSecurity;
this.checkNotSafeValue(value, 'HTML');
return sanitizeHtml(this._doc, String(value));
case SecurityContext.STYLE:
if (value instanceof SafeStyleImpl) return value.changingThisBreaksApplicationSecurity;
this.checkNotSafeValue(value, 'Style');
return sanitizeStyle(value as string);
case SecurityContext.SCRIPT:
if (value instanceof SafeScriptImpl) return value.changingThisBreaksApplicationSecurity;
this.checkNotSafeValue(value, 'Script');
throw new Error('unsafe value used in a script context');
case SecurityContext.URL:
if (value instanceof SafeResourceUrlImpl || value instanceof SafeUrlImpl) {
// Allow resource URLs in URL contexts, they are strictly more trusted.
return value.changingThisBreaksApplicationSecurity;
}
this.checkNotSafeValue(value, 'URL');
return sanitizeUrl(String(value));
case SecurityContext.RESOURCE_URL:
if (value instanceof SafeResourceUrlImpl) {
return value.changingThisBreaksApplicationSecurity;
}
this.checkNotSafeValue(value, 'ResourceURL');
throw new Error(
'unsafe value used in a resource URL context (see http://g.co/ng/security#xss)');
default:
throw new Error(`Unexpected SecurityContext ${ctx} (see http://g.co/ng/security#xss)`);
}
}