Web 開(kāi)發(fā)的身份和數(shù)據(jù)安全_2.密碼加密惹苗、哈希和加鹽

本文主要內(nèi)容:探討密碼加密和安全性殿较。

靜態(tài)數(shù)據(jù)&動(dòng)態(tài)數(shù)據(jù)

靜態(tài)數(shù)據(jù):不活動(dòng)的(或靜止的)數(shù)字?jǐn)?shù)據(jù),存儲(chǔ)在服務(wù)器中桩蓉,例如用于存儲(chǔ)密碼淋纲、個(gè)人資料、或其他應(yīng)用所需數(shù)據(jù)的數(shù)據(jù)庫(kù)院究。

動(dòng)態(tài)數(shù)據(jù):傳輸中的數(shù)據(jù)帚戳,在應(yīng)用和數(shù)據(jù)庫(kù)之間來(lái)回發(fā)送,或者在網(wǎng)站和 API 或外部數(shù)據(jù)源之間來(lái)回傳送儡首。

靜態(tài)數(shù)據(jù)

  • 數(shù)據(jù)庫(kù)加密是絕對(duì)有必要的片任,盡管 99% 的團(tuán)體沒(méi)有這么做。
  • 加密數(shù)據(jù)庫(kù)應(yīng)該使用強(qiáng)加密蔬胯、受 NIST 認(rèn)可的算法对供,如:SHA-256、AES氛濒、RSA产场。
  • 遵循標(biāo)準(zhǔn)做法:1. 分開(kāi)訪問(wèn)控制(用戶登錄)和數(shù)據(jù)加密;2. 定期更新加密數(shù)據(jù)庫(kù)的密鑰舞竿;3. 分開(kāi)存儲(chǔ)加密密鑰和數(shù)據(jù)京景。
  • 對(duì)全球覆蓋的應(yīng)用來(lái)說(shuō),可以使用數(shù)據(jù)聯(lián)合避免惡意訪問(wèn)數(shù)據(jù)存儲(chǔ)器骗奖,在需要個(gè)人信息的不同區(qū)域維護(hù)不同的數(shù)據(jù)庫(kù)系統(tǒng)确徙。
  • 根據(jù)運(yùn)行應(yīng)用、網(wǎng)站或服務(wù)的需要执桌,應(yīng)該盡量少存儲(chǔ)敏感的用戶數(shù)據(jù)鄙皇。
  • 敏感的財(cái)務(wù)信息(例如信用卡數(shù)據(jù))可以交由他方(支付提供商)處理。

動(dòng)態(tài)數(shù)據(jù)

動(dòng)態(tài)數(shù)據(jù)的使用場(chǎng)景:

  • 用戶填寫(xiě)的注冊(cè)信息仰挣,用于訪問(wèn)賬戶和認(rèn)證身份伴逸。
  • 把個(gè)人檔案信息傳輸給API服務(wù),或從中獲取膘壶。
  • 應(yīng)用或網(wǎng)站收集的其他數(shù)據(jù)错蝴,傳給數(shù)據(jù)庫(kù)存儲(chǔ)起來(lái)。

密碼攻擊媒介

  • 釣魚(yú)颓芭;
  • 社會(huì)工程顷锰;
  • 暴力攻擊;(抵抗方式:密鑰延伸技術(shù))
  • 字典攻擊万矾;(抵抗方式:加鹽)
  • 彩虹表;(抵抗方式:加鹽)
  • 惡意軟件慎框;(抵抗方式:短信驗(yàn)證良狈、n因素認(rèn)證)
  • 離線破解;

加鹽

鹽值是一種隨機(jī)數(shù)據(jù)笨枯,計(jì)算密碼的哈希值時(shí)用于加強(qiáng)數(shù)據(jù)薪丁,抵御多種攻擊媒介尤其是字典攻擊和彩虹表。這個(gè)隨機(jī)數(shù)據(jù)(特別長(zhǎng))能確保生成的哈希值是唯一的馅精,即使多個(gè)用戶使用相同的密碼(確實(shí)有這種情況)严嗜,添加唯一的鹽值后能確保得到的哈希值仍是唯一的。就因?yàn)榈玫降墓V凳俏ㄒ坏闹薷遥覀儾诺靡悦馐懿屎绫砗妥值涔舻奈:Α?/p>

鹽值的特點(diǎn):鹽值需要足夠長(zhǎng)漫玄、不可預(yù)測(cè)、高度隨機(jī)压彭、需要使用安全的偽隨機(jī)函數(shù)生成睦优,另外,還要避免使用全局的鹽值壮不。

生成隨機(jī)鹽值

使用 Node 原生支持的的 crypto 庫(kù)生成隨機(jī)鹽值汗盘。

const crypto = require('crypto');

// 1.異步方法生成鹽值
// crypto.randomBytes() 生成 16 位強(qiáng)加密的偽隨機(jī)數(shù)
crypto.randomBytes(16, (err, buf) => {
  if (err) throw err;
  console.log(`${buf.length} bytes of random data: ${buf.toString('hex')}`);
  console.log(`${buf.length} bytes of random data: ${buf.toString('base64')}`);
});

// 2.同步方法生成鹽值
const buf = crypto.randomBytes(256);

重用鹽值

用戶注冊(cè)賬戶或修改密碼時(shí)應(yīng)該生成并存儲(chǔ)新的鹽值和哈希值。

鹽值的長(zhǎng)度

  • 根據(jù)經(jīng)驗(yàn)询一,鹽值的長(zhǎng)度應(yīng)該與哈希函數(shù)的輸出長(zhǎng)度一致隐孽。
  • PBKDF2 標(biāo)準(zhǔn)建議至少應(yīng)該使用 64 位(8字節(jié))長(zhǎng)度的鹽值。通常健蕊,多數(shù)情況下使用的是2的7次方缓醋,即 128 位(16字節(jié))

把鹽值存儲(chǔ)在哪绊诲?

鹽值可以和哈希值一起以明文形式存儲(chǔ)在數(shù)據(jù)庫(kù)中送粱。

salt 不能和哈希值存儲(chǔ)在一起,不然就和沒(méi)有 salt 一樣掂之,因?yàn)楣粽咄蠋?kù)后抗俄,構(gòu)建字典非常簡(jiǎn)單,因?yàn)樗軌蛑苯涌吹?salt世舰,所以一定要分開(kāi)存儲(chǔ)(比如在不同的機(jī)器上)动雹,這樣即使口令密文表被拖庫(kù)了,而 salt 表沒(méi)有被拖庫(kù)跟压,也是相對(duì)安全的胰蝠。

撒胡椒

  • 胡椒是在計(jì)算哈希值時(shí)隨鹽值和密碼一起傳入的值。
  • 使用胡椒的簡(jiǎn)單公式:hash ( salt + pepper + password ) = password hash
  • 胡椒在代碼層計(jì)算,而不是使用存儲(chǔ)的值茸塞。
  • 使用胡椒的原因:利用額外的字符和符號(hào)加強(qiáng)密碼的強(qiáng)度躲庄。

選擇正確的密碼哈希函數(shù)

bcrypt ??????

GitHub 源碼:node.bcrypt.js

特性:專(zhuān)為加密密碼設(shè)計(jì),底層基于 Blowfish 密碼法钾虐,有異步方法和同步方法噪窘、密碼哈希函數(shù)、校驗(yàn)密碼函數(shù)效扫、帶 promise 特性...

const bcrypt = require('bcrypt');

// 封裝 hash 函數(shù)
function bcrypt_encrypt(username, password) {
  // 1. bcrypt 內(nèi)置了生成鹽值的方法:bcrypt.genSalt()
  bcrypt.genSalt(10, (err, salt) => {
    if (err) throw err;
      
    // 2. 生成哈希值:hash()
    bcrypt.hash(password, salt, (err, key) => {
      if (err) throw err;
      
      // 3. 把用戶名倔监、密碼哈希值和鹽值存入數(shù)據(jù)庫(kù)
    });
  });
}

// 調(diào)用示例
bcrypt_encrypt('zhangsan', '123456');

// 對(duì)比哈希值,驗(yàn)證密碼:
bcrypt.compare(password, hash, (err, same) => {
  // 返回 true 或 false
});

PBKDF2

  • 1Password菌仁、LastPass 等密碼管理系統(tǒng)采用的算法浩习;
  • Node.js 中的 crypt 模塊原生支持的標(biāo)準(zhǔn)算法;
  • 通過(guò)該算法可以實(shí)現(xiàn)基于口令的加密(PBE)济丘,即基于口令生成密鑰瘦锹。

加密示例:

// PBKDF2 算法
function pbkdf2_encrypt(username, password) {
  // 1. crypto.randomBytes()方法生成 32 字節(jié)的隨機(jī)鹽值
  crypto.randomBytes(32, (err, salt) => {
    if (err) throw err;

    // 2. 參數(shù)列表:(密碼,鹽值闪盔,迭代次數(shù)弯院,輸出密鑰長(zhǎng)度,摘要算法)
    crypto.pbkdf2(password, salt, 4096, 512, 'sha256', (err, key) => {
      if (err) throw err;
      
      // 3. 將用戶名泪掀、密碼哈希值和鹽值存入數(shù)據(jù)庫(kù)
      // Salt 鹽值是明文保存的听绳,一般不和最終生成的密鑰保存在一起。
      console.log(username, key.toString('hex'), salt.toString('hex'));
    });
  });
}

// 調(diào)用示例
pbkdf2_encrypt('zhangSan', '123456');

對(duì)比哈希值异赫,驗(yàn)證密碼:

const dbsalt = 'USER RECORD SALT FROM YOUR DATABASE';
const dbhash = 'USER RECORD KEY FROM YOUR DATABASE';

crypto.pbkdf2(password, dbsalt, 4096, 512, 'sha256', (err, comparsehash) => {
  if (err) throw err;

  // 比較
  if (dbhash.toString('hex') === comparsehash.toString('hex')) {
    // 密碼匹配
  } else {
    // 密碼不匹配
  }
});

scrypt

GitHub 源碼:node-scrypt

scrypt 的優(yōu)勢(shì)和實(shí)現(xiàn)如下:

  • 做了特殊設(shè)計(jì)椅挣,是硬件和內(nèi)存密集型算法,攻擊者要實(shí)施大型攻擊塔拳,想要破解需要耗費(fèi)異常多的硬件和內(nèi)存鼠证。
  • 是加密數(shù)字貨幣萊特幣和狗狗幣背后采用的算法。
'use strict';

const scrypt = require('scrypt');
const crypto = require('crypto');

function scrypt_encrypt(username, password) {
  // 1. 使用 crypto 的 crypto.randomBytes(...) 方法生成鹽值靠抑。
  crypto.randomBytes(32, (err, salt) => {
    if (err) throw err;

    // 2. scrypt.hash(...) 生成 64 位的哈希值
    // - N: scrypt 最多使用多長(zhǎng)時(shí)間(秒數(shù))計(jì)算密鑰(偶數(shù))量九。
    // - r:計(jì)算密鑰時(shí)最多使用多少字節(jié) RAM(整數(shù))。默認(rèn)為0颂碧。
    // - p:計(jì)算密鑰時(shí)所用 RAM 占可用值的比例(0-1荠列,換算成百分比)默認(rèn)為0.5。
    scrypt.hash(password, {"N":16384,"r":8,"p":1}, 64, salt, (err, key) => {
      if (err) throw err;

      // 3. 把用戶名载城、密碼哈希值和鹽值存入數(shù)據(jù)庫(kù)
      console.log(`key is ${key}`);
    });
  });
}

密鑰延伸

bcrypt肌似、scrypt 和 PBKDF2 行之有效涉及到的底層概念——密鑰延伸(Key Derivation Function,KDF)诉瓦。
密鑰延伸:把弱密碼變成特別復(fù)雜的長(zhǎng)密碼川队,致使暴力攻擊等攻擊媒介不再可行力细。

對(duì)加密哈希函數(shù)來(lái)說(shuō),密鑰延伸體現(xiàn)在不斷循環(huán)應(yīng)用哈希函數(shù)(哈希函數(shù)迭代)固额,直到得到所需長(zhǎng)度和復(fù)雜度的哈希值為止眠蚂。

重新計(jì)算哈希值

有時(shí)可能需要為用戶生成新的密碼哈希值。比如說(shuō):

  • 根據(jù)摩爾定律对雪,硬件更新了河狐,要修改加密算法使用的權(quán)重/工作因子米绕。
  • 算法變了瑟捣,或者有更好的算法出現(xiàn),目前使用的算法不安全栅干。
  • 覺(jué)得現(xiàn)有哈希值不再安全迈套。

遇到這些情況,符合常規(guī)的做法是為用戶生成新哈希值碱鳞,存儲(chǔ)在系統(tǒng)中桑李。用戶提供用戶名和密碼請(qǐng)求登錄時(shí),正常比較根據(jù)輸入值計(jì)算的哈希值和存儲(chǔ)的哈希值窿给,而不是拒絕登錄贵白。隨后,為用戶生成新的哈希值崩泡,替換用戶記錄中的舊值禁荒。

參考

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末角撞,一起剝皮案震驚了整個(gè)濱河市呛伴,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌谒所,老刑警劉巖热康,帶你破解...
    沈念sama閱讀 216,997評(píng)論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異劣领,居然都是意外死亡姐军,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,603評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門(mén)尖淘,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)庶弃,“玉大人,你說(shuō)我怎么就攤上這事德澈⌒ィ” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 163,359評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵梆造,是天一觀的道長(zhǎng)缴守。 經(jīng)常有香客問(wèn)我葬毫,道長(zhǎng),這世上最難降的妖魔是什么屡穗? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,309評(píng)論 1 292
  • 正文 為了忘掉前任贴捡,我火速辦了婚禮,結(jié)果婚禮上村砂,老公的妹妹穿的比我還像新娘烂斋。我一直安慰自己,他們只是感情好础废,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,346評(píng)論 6 390
  • 文/花漫 我一把揭開(kāi)白布汛骂。 她就那樣靜靜地躺著,像睡著了一般评腺。 火紅的嫁衣襯著肌膚如雪帘瞭。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,258評(píng)論 1 300
  • 那天蒿讥,我揣著相機(jī)與錄音蝶念,去河邊找鬼。 笑死芋绸,一個(gè)胖子當(dāng)著我的面吹牛媒殉,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播摔敛,決...
    沈念sama閱讀 40,122評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼廷蓉,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了舷夺?” 一聲冷哼從身側(cè)響起苦酱,我...
    開(kāi)封第一講書(shū)人閱讀 38,970評(píng)論 0 275
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎给猾,沒(méi)想到半個(gè)月后疫萤,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,403評(píng)論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡敢伸,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,596評(píng)論 3 334
  • 正文 我和宋清朗相戀三年扯饶,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片池颈。...
    茶點(diǎn)故事閱讀 39,769評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡尾序,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出躯砰,到底是詐尸還是另有隱情每币,我是刑警寧澤,帶...
    沈念sama閱讀 35,464評(píng)論 5 344
  • 正文 年R本政府宣布琢歇,位于F島的核電站兰怠,受9級(jí)特大地震影響梦鉴,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜揭保,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,075評(píng)論 3 327
  • 文/蒙蒙 一肥橙、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧秸侣,春花似錦存筏、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,705評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至励负,卻和暖如春藕溅,著一層夾襖步出監(jiān)牢的瞬間匕得,已是汗流浹背继榆。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,848評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留汁掠,地道東北人略吨。 一個(gè)月前我還...
    沈念sama閱讀 47,831評(píng)論 2 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像考阱,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,678評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容