淺談 Web 安全

meils發表於2019-03-15

我們多少應該聽說過一些關於web安全的問題吧,比如http劫持xss跨站指令碼攻擊corf跨站請求偽造。當下好多的網站都沒有實現https,web安全也是一個非常重要的話題。

一、Http劫持

在使用者的客戶端與其要訪問的伺服器經過網路協議協調後,二者之間建立了一條專用的資料通道,使用者端程式在系統中開放指定網路埠用於接收資料包文,伺服器端將全部資料按指定網路協議規則進行分解打包,形成連續資料包文。

使用者端接收到全部報文後,按照協議標準來解包組合獲得完整的網路資料。其中傳輸過程中的每一個資料包都有特定的標籤,表示其來源、攜帶的資料屬性以及要到何處,所有的資料包經過網路路徑中ISP的路由器傳輸接力後,最終到達目的地,也就是客戶端。

HTTP劫持 是在使用者與其目的網路服務所建立的專用資料通道中,監視特定資料資訊,提示當滿足設定的條件時,就會在正常的資料流中插入精心設計的網路資料包文,目的是讓使用者端程式解釋“錯誤”的資料,並以彈出新視窗的形式在使用者介面展示宣傳性廣告或者直接顯示某網站的內容。

二、DNS劫持

DNS 劫持就是通過劫持了 DNS 伺服器,通過某些手段取得某域名的解析記錄控制權,進而修改此域名的解析結果,導致對該域名的訪問由原IP地址轉入到修改後的指定IP,其結果就是對特定的網址不能訪問或訪問的是假網址,從而實現竊取資料或者破壞原有正常服務的目的。

DNS 劫持比之 HTTP 劫持 更加過分,簡單說就是我們請求的是 http://www.a.com/index.html ,直接被重定向了 http://www.b.com/index.html

三、XSS攻擊

xss就是攻擊者利用漏洞,向我們的頁面注入一些攻擊性指令碼,當使用者瀏覽頁面的時候自動觸發執行,從而達到攻擊的目的。

HTTP 劫持 和 XSS 最終都是惡意程式碼在客戶端,通常也就是使用者瀏覽器端執行,我們應該學會即使我們被攻擊了,我們應該如何利用 Javascript 進行行之有效的前端防護。

頁面被嵌入 iframe 中,重定向 iframe

先來說說我們的頁面被嵌入了 iframe 的情況。也就是,網路運營商為了儘可能地減少植入廣告對原有網站頁面的影響,通常會通過把原有網站頁面放置到一個和原頁面相同大小的 iframe 裡面去,那麼就可以通過這個 iframe 來隔離廣告程式碼對原有頁面的影響。

淺談 Web 安全

這種情況還比較好處理,我們只需要知道我們的頁面是否被巢狀在 iframe 中,如果是,則重定向外層頁面到我們的正常頁面即可。

那麼有沒有方法知道我們的頁面當前存在於 iframe 中呢?有的,就是 window.self 與 window.top 。

window.self
返回一個指向當前 window 物件的引用。

window.top
返回視窗體系中的最頂層視窗的引用。
複製程式碼
// 我們可以通過如下判斷來區分是否外部被巢狀iframe
if (self != top) {
  // 我們的正常頁面
  var url = location.href;
  // 父級頁面重定向
  top.location = url;
}
複製程式碼

內聯事件及內聯指令碼攔截

列出一些比較常見的注入方式:

<a href="javascript:alert(1)" ></a>
<iframe src="javascript:alert(1)" />
<img src='x' onerror="alert(1)" />
<video src='x' onerror="alert(1)" ></video>
<div onclick="alert(1)" onmouseover="alert(2)" ><div>
複製程式碼

除去一些未列出來的非常少見生僻的注入方式,大部分都是 javascript:...及內聯事件 on*

我們假設注入已經發生,那麼有沒有辦法攔截這些內聯事件與內聯指令碼的執行呢?

對於上面列出的 (1) (5) ,這種需要使用者點選或者執行某種事件之後才執行的指令碼,我們是有辦法進行防禦的。

以攔截 javascript:為例子。

// 建立關鍵詞黑名單
var keywordBlackList = [
  'xss',
  'BAIDU_SSP__wrapper',
  'BAIDU_DSPUI_FLOWBAR'
];
   
document.addEventListener('click', function(e) {
  var code = "";
 
  // 掃描 <a href="javascript:"> 的指令碼
  if (elem.tagName == 'A' && elem.protocol == 'javascript:') {
    var code = elem.href.substr(11);
 
    if (blackListMatch(keywordBlackList, code)) {
      // 登出程式碼
      elem.href = 'javascript:void(0)';
      console.log('攔截可疑事件:' + code);
    }
  }
}, true);
 
/**
 * [黑名單匹配]
 * @param  {[Array]} blackList [黑名單]
 * @param  {[String]} value    [需要驗證的字串]
 * @return {[Boolean]}         [false -- 驗證不通過,true -- 驗證通過]
 */
function blackListMatch(blackList, value) {
  var length = blackList.length,
    i = 0;
 
  for (; i < length; i++) {
    // 建立黑名單正則
    var reg = new RegExp(whiteList[i], 'i');
 
    // 存在黑名單中,攔截
    if (reg.test(value)) {
      return true;
    }
  }
  return false;
}
複製程式碼

靜態指令碼攔截

XSS 跨站指令碼的精髓不在於“跨站”,在於“指令碼”。

通常而言,攻擊者或者運營商會向頁面中注入一個<script>指令碼,具體操作都在指令碼中實現,這種劫持方式只需要注入一次,有改動的話不需要每次都重新注入。 比如:

<div id="wrapper">
    111
    <script>alert('xss');</script>
</div>
複製程式碼

頁面中如果有這麼一段,那麼頁面會執行alert函式。

如果是:

<div id="wrapper">
      &lt;script&gt;alert(1)&lt;&#x2F;script&gt;
  </div>
複製程式碼

頁面則不會執行。

所以最普遍的做法是轉義輸入輸出的內容,對於引號,尖括號,斜槓進行轉義

function escape(str) {
  str = str.replace(/&/g, '&amp;')
  str = str.replace(/</g, '&lt;')
  str = str.replace(/>/g, '&gt;')
  str = str.replace(/"/g, '&quto;')
  str = str.replace(/'/g, '&#39;')
  str = str.replace(/`/g, '&#96;')
  str = str.replace(/\//g, '&#x2F;')
  return str
}
複製程式碼

我們一般使用一個現成的工具:

XSS是一個用於對使用者輸入的內容進行過濾,以避免遭受XSS攻擊的模組 (什麼是XSS攻擊?)。主要用於論壇、部落格、網上商店等等一些可允許使用者錄入頁面排版、 格式控制相關的HTML的場景,xss模組通過白名單來控制允許的標籤及相關的標籤屬性, 另外還提供了一系列的介面以便使用者擴充套件,比其他同類模組更為靈活。

xss.js

相關文章