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>
我需要做一个像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>