每個 node 應用可能存在的 timing-attack 安全漏洞

創宇前端發表於2019-02-22

前言

假如你在專案中遇到過 eslint 報錯 Potential timing attack ,不可忽視!這是一個涉及到安全的問題:時序攻擊。

eslint 報錯原因

  • 首先eslint引入了一個叫做eslint-plugin-security的外掛,這個外掛有助於識別出潛在的安全問題,但同時也會產生誤報的問題,附上外掛 原始碼地址
  var keywords = `((` + [
    `password`,
    `secret`,
    `api`,
    `apiKey`,
    `token`,
    `auth`,
    `pass`,
    `hash`
  ].join(`)|(`) + `))`;

  var re = new RegExp(`^` + keywords + `$`, `im`);

  function containsKeyword (node) {
    if (node.type === `Identifier`) {
      if (re.test(node.name)) return true;
    }
    return
  }


  if (node.test.operator === `==` || node.test.operator === `===` || node.test.operator === `!=` || node.test.operator === `!==`) {
    // 在這裡 console 出錯誤
  }
複製程式碼

首先這個外掛會判斷本次的運算子是否為 ==、===、!=、!==其中一種,其次檢查識別符號(欄位名)是否包含特殊字串password、secret、api、apiKey、token、auth、pass、hash,如果同時滿足二者情況,eslint 就會編譯報錯 Potential timing attack

攻擊定義

timing attack:時序攻擊,屬於側通道攻擊 / 旁路攻擊,側通道攻擊指的是利用通道外的資訊,比如加解密的資料、資料比較時間、密文傳輸的流量和途徑進行攻擊的方式,相當於是“旁敲側擊”。

攻擊點

  • 首先講講js比較兩個字串大小的原理:

    • 判斷字串長度是否為0,如果為0,就可以直接比較出結果;反之,進入到第二步。
    • 字串是由一個個字元組成,通過每個字元的charCode進行比較。
    • 在第二步中,只要出現一個字元不同,就 return false,剩餘的字元不再做比較。
  • 單個字元的比較是很快的,攻擊者可以細化測量時間精度到微秒,通過響應時間的差異推算出是從哪一個字元開始不用的,這樣一次次實驗或者用 Python 寫個指令碼去跑,就可以試出正確的密碼,密碼破解的難度也降低了不少。

容易受攻擊的寫法

  if (user.password === password) {
    return { state: true }; // 登入成功
  }
複製程式碼

防禦措施

每次不同的輸入會造成處理時間的不同。為了防止它,我們需要使字串比較花費相同的時間量,無論輸入的密碼是什麼。

不容易受攻擊的寫法

系統中每一個密碼的長度是固定的,每次比較密碼是否相同時,使用正確密碼的長度作為比較次數,使用異或比較每一個字元的 Unicode 編碼是否相等,並且把每一次的比較結果存放到一個陣列中,最後再判斷陣列的每一個元素是否為0(為 0 表示兩個字元相同)

  // psdReceived 為使用者輸入密碼;
  // psdDb 為系統中儲存的正確使用者密碼
  const correctUser = (psdDb, psdReceived) => {
    const state = [];
    for (let i = 0; i < psdDb.length; ++i) {
      if (!psdReceived[i]) {
        state.push(false);
      } else {
        state.push(psdReceived.charCodeAt(i) ^ psdDb.charCodeAt(i));
      }
    }
    return state.length !== 0 && state.every(item => !item);
  }
複製程式碼

三方包推薦

也可以使用 cryptiles 這個 npm 模組來解決這個問題

import cryptiles from `cryptiles`;

......
return cryptiles.fixedTimeCimparison(passwordFromDb, passwordReceived);
複製程式碼

關注微信公眾號:創宇前端(KnownsecFED),碼上獲取更多優質乾貨!

每個 node 應用可能存在的 timing-attack 安全漏洞

相關文章