從頭到腳實現一個 XSS-Filter

上文中,咱們已經熟悉了 XSS 攻擊的定義、分類以及防禦手段了,咱們知道 XSS 防禦最重要和有效的手段就是進行 XSS-Filter 處理。既然 XSS-Filter 如此重要,那咱們怎麼開發一個 XSS-Filter 庫呢?這篇文章會告訴你答案,如今就跟隨我,一步步開發一個 XSS-Filter 吧?javascript

其實對於一個 XSS-Filter 來講,無非就是作字符串替換的操做,即:java

replace(/a/, /b/);
複製代碼

也就是說,咱們要作的就是將一些字符串替換成另一些字符串。這樣咱們能夠找到那些可能引起安全問題的標籤或者屬性替換成(轉義成)安全的字符,或者將除了某些安全標籤或屬性以外的其餘字符都進行轉義或過濾。這樣一來就對應兩種思路,即:git

  • 黑名單的技術
  • 白名單的技術 咱們先簡單介紹一下這兩種技術。

黑名單技術

在計算機安全中,黑名單只是一種防止已知惡意程序運行的簡單有效的方法,更新黑名單能夠快速經過更新服務器來實現,大多數防病毒程序使用的是黑名單技術來阻止已知威脅,垃圾郵件過濾器每每須要依賴於黑名單技術。 黑名單技術只在某些應用中可以發揮良好做用,固然前提是黑名單內容準確性和完整性。 黑名單最重要的問題就是,它只能抵禦已知的有害的程序和發送者,不可以抵禦新威脅(零日攻擊等),對進入網絡的流量進行掃描並將其與黑名單對比還可能浪費至關多的資源以及下降網絡流量。github

白名單技術

白名單技術的宗旨是不阻止某些特定的事物,它採起了與黑名單相反的作法,利用一份「已知爲良好」的實體(程序、電子郵件地址、域名、網址)名單,如下是白名單技術的優勢:安全

  • 沒有必要運行必須不斷更新的防病毒軟件,任何不在名單上的事物將被阻止運行;
  • 系統可以免受零日攻擊。
  • 用戶不可以運行不在名單上的未經受權的程序

白名單技術的優勢是,除了名單上的實體外都不能運行或者經過,缺點則是,不在名單上的實體都不能運行和經過。可見,優勢也是缺點。服務器

技術選擇

咱們已經瞭解了黑名單和白名單兩種技術了。在實現 XSS-Filter 時,對比了黑名單和白名單的特色,咱們應該選擇白名單來實現,緣由以下:網絡

  • 使用黑名單,沒法應對將來出現的威脅,將來可能新增一些存在安全威脅的標籤或屬性;
  • 黑名單內容準確性和完整性很難作到。 而使用白名單,不存在未知的威脅,全部可以經過的,都是安全的,這樣能夠極大增長系統的安全性。接下來咱們一塊兒看看一個可用白名單。
/* * { * key: value * } * key 標籤名 value 支持的屬性列表 */
var whiteList = {
  a: ['target', 'href', 'title'],
  abbr: ['title'],
  address: [],
  area: ['shape', 'coords', 'href', 'alt'],
  article: [],
  aside: [],
  audio: ['autoplay', 'controls', 'loop', 'preload', 'src'],
  b: [],
  bdi: ['dir'],
  bdo: ['dir'],
  big: [],
  blockquote: ['cite'],
  br: [],
  caption: [],
  center: [],
  cite: [],
  code: [],
  col: ['align', 'valign', 'span', 'width'],
  colgroup: ['align', 'valign', 'span', 'width'],
  dd: [],
  del: ['datetime'],
  details: ['open'],
  div: [],
  dl: [],
  dt: [],
  em: [],
  font: ['color', 'size', 'face'],
  footer: [],
  h1: [],
  h2: [],
  h3: [],
  h4: [],
  h5: [],
  h6: [],
  header: [],
  hr: [],
  i: [],
  img: ['src', 'alt', 'title', 'width', 'height'],
  ins: ['datetime'],
  li: [],
  mark: [],
  nav: [],
  ol: [],
  p: [],
  pre: [],
  s: [],
  section: [],
  small: [],
  span: [],
  sub: [],
  sup: [],
  strong: [],
  table: ['width', 'border', 'align', 'valign'],
  tbody: ['align', 'valign'],
  td: ['width', 'rowspan', 'colspan', 'align', 'valign'],
  tfoot: ['align', 'valign'],
  th: ['width', 'rowspan', 'colspan', 'align', 'valign'],
  thead: ['align', 'valign'],
  tr: ['rowspan', 'align', 'valign'],
  tt: [],
  u: [],
  ul: [],
  video: ['autoplay', 'controls', 'loop', 'preload', 'src', 'height', 'width']
};
複製代碼

如何經過白名單過濾標籤

咱們首先將輸入的 HTML Dom String 轉化爲 HTML 標籤以及 HTML 屬性,而後再經過白名單將 HTML 標籤和屬性轉換。 好比咱們能夠這麼作:dom

// 輸入HTML Dom String
var domString = '<div><a></a><script></script></div>';
// 找到第一個標籤 div, 在白名單裏,不作轉義操做

...
// 找到第*個標籤 script,不在白名單裏,作轉義操做
<script> ===>  &lt;script&gt;

複製代碼

對屬性的處理也相似,咱們尤爲注意對 src 和 href 屬性的處理。xss

function safeAttrValue(name, value) {

  var Reg = /((j\s*a\s*v\s*a|v\s*b|l\s*i\s*v\s*e)\s*s\s*c\s*r\s*i\s*p\s*t\s*|m\s*o\s*c\s*h\s*a)\:/gi;

  if (name === "href" || name === "src") {

    value = value.trim();
    if (value === "#") return "#";
    if (
      !(
        value.substr(0, 7) === "http://" ||
        value.substr(0, 8) === "https://" ||
        value.substr(0, 7) === "mailto:" ||
        value.substr(0, 4) === "tel:" ||
        value[0] === "#" ||
        value[0] === "/"
      )
    ) {
      // 若是href和src屬性不是連接則清空,防止href="javascript:alert(/xss/)"這種情形
      return "";
    }
  } else if (name === "background") {

    if (reg.test(value)) {
      // 若是包含javascript腳本則清空
      return "";
    }
  }

  // escape `<>"` before returns
  var REGEXP_QUOTE = /"/g;
  var REGEXP_LT = /</g;
  var REGEXP_GT = />/g;
  value =value.replace(, "&quot;").replace(REGEXP_LT, "&lt;").replace(REGEXP_GT, "&gt;");
  return value;
}
複製代碼

總體的流程以下圖所示: ide

固然,實現一個XSS-Filter要考慮的東西遠遠要多不少,這裏主要是給你們提供一個思路,具體的源碼你們能夠參見網上一個比較流行的XSS庫的實現,倉庫,這裏的源碼都是用es5語法寫的,總體看起來比較凌亂,你們有興趣能夠用最新的ES6語法寫個相似的倉庫。

結語

又到告終尾了,很開心你們能堅持看到最後。XSS防護仍是很值得你們去深刻研究的,總之一句話,但願咱們你們能從個人文章學到知識。最後,祝你們工做愉快!

@Author: WaterMan

相關文章
相關標籤/搜索