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

前言

假如你在項目中遇到過 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 attacknode

攻擊定義

timing attack:時序攻擊,屬於側信道攻擊 / 旁路攻擊,側信道攻擊指的是利用信道外的信息,好比加解密的數據、數據比較時間、密文傳輸的流量和途徑進行攻擊的方式,至關因而「旁敲側擊」。git

攻擊點

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

    • 判斷字符串長度是否爲0,若是爲0,就能夠直接比較出結果;反之,進入到第二步。
    • 字符串是由一個個字符組成,經過每一個字符的charCode進行比較。
    • 在第二步中,只要出現一個字符不一樣,就 return false,剩餘的字符再也不作比較。
  • 單個字符的比較是很快的,攻擊者能夠細化測量時間精度到微秒,經過響應時間的差別推算出是從哪個字符開始不用的,這樣一次次實驗或者用 Python 寫個腳本去跑,就能夠試出正確的密碼,密碼破解的難度也下降了很多。npm

容易受攻擊的寫法

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

防護措施

每次不一樣的輸入會形成處理時間的不一樣。爲了防止它,咱們須要使字符串比較花費相同的時間量,不管輸入的密碼是什麼。api

不容易受攻擊的寫法

系統中每個密碼的長度是固定的,每次比較密碼是否相同時,使用正確密碼的長度做爲比較次數,使用異或比較每個字符的 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),碼上獲取更多優質乾貨!微信

相關文章
相關標籤/搜索