最先在大學的時候,只知道用 MD5 來存用戶的帳號的密碼,但其實這很是不安全,而所用到的哈希函數,深刻挖掘,也發現並不簡單……html
哈希(散列)函數是什麼就不贅述了。前端
RC4, MD4, MD5, SHA-0, SHA-1, DES, 2DES 等node
SHA-2(SHA-256, SHA-384, SHA-512)、SHA-三、Blake2 等算法
美國國家標準和技術協會(NIST)宣佈,2010 年後開始逐步取消 SHA-1 做爲安全哈希算法的資格,取而代之的是其更強大的變異算法:SHA-22四、SHA-25六、SHA-384 和 SHA-512。不管是否遵循 NIST 的標準,至少使用 SHA-256 算法加密密碼老是好的。npm
就像攻與矛的互相加強,哈希函數哪怕用到 SHA-3 以上,都仍是有被輕易破解的風險。因而咱們有其餘額外的辦法來解決這個問題。後端
加鹽就是對目標字段哈希前,拼接上另外一個字段(salt)。安全
注:鹽值加到字段以前較爲廣泛。dom
加鹽對防彩虹表頗有效。async
注意點:函數
鹽的本質是將
無差異攻擊
轉化爲針對性攻擊
。
HMAC
(Keyed-Hashing for Message Authentication)其實也是一種特殊的加鹽,只是這個 salt 用更安全的密鑰代替了。
具體介紹能夠看我以前一篇:《破解另外一家網站的反爬機制 & HMAC 算法》
高端的顯卡(GPU)和定製的硬件能夠每秒進行數十億次哈希計算,所以這類攻擊依然能夠很高效。爲了下降攻擊者的效率,咱們可使用慢哈希,即迭代進行不少次哈希運算。
那麼迭代多少次比較安全呢?來自 NIST 官方的建議:
密碼哈希函數(Password Hash)
能夠用來應對普通哈希容易被破解的問題(也用到了上面所提到的兩個策略)。
下面列舉的順序是按照時間順序,安全程度和推薦指數也逐級遞增。
比較老,不多有人用了,略。
這是我司目前用的。(不過有過期的隱患,建議換掉)
bcrypt 是由 Niels Provos 和 DavidMazières 基於 Blowfish 密碼設計的密碼哈希函數,於 1999 年在 USENIX 上提出。
bcrypt 函數是 OpenBSD 和其餘系統(包括某些 Linux 發行版,例如 SUSE Linux)的默認密碼哈希算法。
安裝:npm i bcryptjs
bcryptjs
跟 C++ 的 bcrypt 兼容,但由於是純 JavaScript 編寫的,所以速度較慢(約 30%)。
用法:
Sync 方法(Async 方法略): const bcryptjs = require('bcryptjs'); // 一、生成 安全因子 const salt = bcrypt.genSaltSync(10); // 二、執行 哈希函數 const password = bcryptjs.hashSync(plainPassword, bcryptjs.genSaltSync(salt)); // 另外一種方法:快速執行 const SALT_FACTOR = 10; const password = bcryptjs.hashSync(plainPassword, bcryptjs.genSaltSync(SALT_FACTOR)); // 三、比較是否相等 bcryptjs.compareSync(plainPassword, password);
注:代碼裏出現的安全因子
,值的大小決定了哈希函數會有多慢。(即慢哈希)
沒用過,略。
2013 年 NIST(美國國家標準與技術研究院)邀請了一些密碼學家一塊兒,舉辦了密碼哈希競賽 PHC(Password Hashing Competition)
。Argon2 在 2015 年 7 月贏得了冠軍。
大賽列出了參賽算法可能面臨的攻擊手段:
一、準備
You can skip this section if the prebuilt binaries work for you. You MUST have a node-gyp global install before proceeding with install, along with GCC >= 5 / Clang >= 3.3. On Windows, you must compile under Visual Studio 2015 or newer. node-argon2 works only and is tested against Node >=10.0.0. --- OSX To install GCC >= 5 on OSX, use homebrew: $ brew install gcc Once you've got GCC installed and ready to run, you then need to install node-gyp, you must do this globally: $ npm install -g node-gyp Finally, once node-gyp is installed and ready to go, you can install this library, specifying the GCC or Clang binary to use: $ CXX=g++-6 npm install argon2 NOTE: If your GCC or Clang binary is named something different than g++-6, you'll need to specify that in the command.
二、安裝
npm i argon2
三、使用
const argon2 = require('argon2'); (async () => { try { // const hash = await argon2.hash("password"); // 更多選項(如下都是默認值) const hash = await argon2.hash("password", { type: argon2.argon2i, hashLength: 32, // 哈希函數輸出的字節長度(請注意,生成的哈希是使用Base64編碼的,所以長度將增長約1/3) timeCost : 3, // 時間成本是哈希函數使用的經過次數(迭代次數) memoryCost: 2 ** 16, // 默認 4096(單位 KB,即 4MB) parallelism :1, //用於計算哈希值的線程數量。每一個線程都有一個具備memoryCost大小的內存池 }) console.log("hash", hash) const is = await argon2.verify(hash, "password") console.log("is", is) // true } catch (err) { console.error("err", err) } })()
一、type:
argon2d
更快且對GPU攻擊具備高度抵抗力,這對於加密貨幣頗有用argon2i
速度較慢且能夠抵禦權衡攻擊,所以首選用於密碼哈希和密鑰派生argon2id
是上述內容的混合組合,能夠抵抗GPU和權衡攻擊由於咱們是用於密碼的 hash,用默認的 argon2i 便可。
二、(慢)哈希相關參數
① memoryCost
內存開銷,它定義了內存的使用狀況
好的起點是 0.75 *(RAM / number_of_users) 起步。
② parallelism
並行程度,它定義了線程的數量
最佳起點是內核數。
③ timeCost
時間開銷,它定義了執行的時間
建議在系統上運行它,並肯定與內存和處理器使用時間限制相匹配的最大參數。
如前所述,本質是在安全性和可用性之間取得平衡。
三、其餘參數
salt:默認值是未設置,將生成加密安全的隨機鹽。
saltLength:默認16。
version:您不該更改此設置,由於最新版本更強大。
上面介紹了 2、應對普通哈希容易被破解的策略 ,咱們能夠看看密碼哈希是如何運用並符合這些策略的。
密碼哈希使用 CSPRNG(Cryptographically Secure Pseudo-Random Number Generator)密碼學安全僞隨機數生成器
生成鹽。
CSPRNG 是加密安全(Cryptographically Secure)
的,(加密安全的意思即)意味着用它產生的隨機數更加隨機,且不可預測。
普通的計算機隨機數算法並非很隨機。
注:鹽值自己就在存在於哈希後的字符串中(其實還可能包括版本、慢哈希迭代次數等),當調用跟明文比對的方法時,模塊內部會提取出鹽值進行驗證。
Bcryoy 的安全因子和 Argon2的 timeCost 參數,都是針對慢哈希的配置。
我司使用的 Bcrypt 其實在今年(2020年),已經不安全了,推薦至少使用 Scrypt,有條件上 Argon2。
問1:我用我本身實現哈希算法,不用公開現成的,越古怪越好,壞人不就猜不到了嗎?
答:不建議。
首先介紹下密碼學上的柯克霍夫原則
(Kerckhoffs's principle,也稱爲柯克霍夫假說、公理、或定律),由奧古斯特·柯克霍夫在 19 世紀提出:即便密碼系統的任何細節已爲人悉知,只要密匙(key,又稱密鑰或祕鑰)未泄漏,它也應是安全的。信息論的發明者克勞德·香農則改爲說:「敵人瞭解系統」,這樣的說法則稱爲香農箴言
。
基於這個原則:
問2:既然如今都是 https,前端傳給後端的明文密碼,就懶得加哈希了,能夠嗎?
仍是建議前端也進行哈希(雖然前端的哈希算法容易暴露)。不要漏掉任何一個環節。
Dropbox 公司曾公開分享過本身對用戶帳號的密碼加密的策略,使用了三層加密:
即明文密碼。
在 bcrypt 前作 SHA512,是由於有些 bcrypt 實現會把散列值長度截至 72 字節,從而下降了密碼的熵值,而有的則容許變長密碼,這樣容易受到 DoS 攻擊。使用 SHA512 散列能夠獲得固定長度的 512 字節散列值,避免了上述的兩個問題。
」而有的則容許變長密碼,這樣容易受到 DoS 攻擊「,這句話我不是很理解,待寫。
上面說過,不贅述了。
AES256 會用到密鑰,俗稱胡椒粉(pepper)。密鑰須要被單獨存儲,最好存儲在外部系統:如物理上隔離的服務端、甚至特殊的硬件設備(如 YubiHSM) 。
這裏的 AES256 也能夠用 HMAC 代替。不過前者安全性更好些。