簡(jiǎn)介
MD5(Message-Digest Algorithm)是計(jì)算機(jī)安全領(lǐng)域廣泛使用的散列函數(shù)(又稱哈希算法较木、摘要算法)红符,主要用來(lái)確保消息的完整和一致性。常見(jiàn)的應(yīng)用場(chǎng)景有密碼保護(hù)伐债、下載文件校驗(yàn)等预侯。
特點(diǎn)
- 運(yùn)算速度快:對(duì)
jquery.js
求md5值,57254個(gè)字符峰锁,耗時(shí)1.907ms - 輸出長(zhǎng)度固定:輸入長(zhǎng)度不固定萎馅,輸出長(zhǎng)度固定(128位)。
- 運(yùn)算不可逆:已知運(yùn)算結(jié)果的情況下虹蒋,無(wú)法通過(guò)通過(guò)逆運(yùn)算得到原始字符串校坑。
- 高度離散:輸入的微小變化拣技,可導(dǎo)致運(yùn)算結(jié)果差異巨大。
- 弱碰撞性:不同輸入的散列值可能相同耍目。
應(yīng)用場(chǎng)景
- 文件完整性校驗(yàn):比如從網(wǎng)上下載一個(gè)軟件,一般網(wǎng)站都會(huì)將軟件的md5值附在網(wǎng)頁(yè)上徐绑,用戶下載完軟件后邪驮,可對(duì)下載到本地的軟件進(jìn)行md5運(yùn)算,然后跟網(wǎng)站上的md5值進(jìn)行對(duì)比傲茄,確保下載的軟件是完整的(或正確的)
- 密碼保護(hù):將md5后的密碼保存到數(shù)據(jù)庫(kù)毅访,而不是保存明文密碼,避免拖庫(kù)等事件發(fā)生后盘榨,明文密碼外泄喻粹。
node中使用md5
在nodejs中,crypto
模塊封裝了一系列密碼學(xué)相關(guān)的功能草巡,包括摘要運(yùn)算守呜。基礎(chǔ)例子如下山憨,非常簡(jiǎn)單:
var crypto = require('crypto');
var md5 = crypto.createHash('md5');
var result = md5.update('a').digest('hex');
// 輸出:0cc175b9c0f1b6a831c399e269772661
console.log(result);
安全性
單純對(duì)密碼進(jìn)行md5不安全
相同的明文密碼查乒,md5值也是相同的。
當(dāng)攻擊者知道算法是md5郁竟,且數(shù)據(jù)庫(kù)里存儲(chǔ)的密碼值為e10adc3949ba59abbe56e057f20f883e時(shí)玛迄,理論上可以可以猜到,用戶的明文密碼就是123456棚亩。
事實(shí)上蓖议,彩虹表就是這么進(jìn)行暴力破解的:事先將常見(jiàn)明文密碼的md5值運(yùn)算好存起來(lái),然后跟網(wǎng)站數(shù)據(jù)庫(kù)里存儲(chǔ)的密碼進(jìn)行匹配讥蟆,就能夠快速找到用戶的明文密碼勒虾。
提高安全性
**密碼加鹽 ***
就是在密碼特定位置插入特定字符串后,再對(duì)修改后的字符串進(jìn)行md5運(yùn)算攻询。
var crypto = require('crypto');
function cryptPwd(password, salt) {
// 密碼“加鹽”
var saltPassword = password + ':' + salt;
console.log('原始密碼:%s', password);
console.log('加鹽后的密碼:%s', saltPassword);
// 加鹽密碼的md5值
var md5 = crypto.createHash('md5');
var result = md5.update(saltPassword).digest('hex');
console.log('加鹽密碼的md5值:%s', result);
}
cryptPwd('123456', 'abc');
// 輸出:
// 原始密碼:123456
// 加鹽后的密碼:123456:abc
// 加鹽密碼的md5值:51011af1892f59e74baf61f3d4389092
cryptPwd('123456', 'bcd');
// 輸出:
// 原始密碼:123456
// 加鹽后的密碼:123456:bcd
// 加鹽密碼的md5值:55a95bcb6bfbaef6906dbbd264ab4531
** 密碼加鹽:隨機(jī)鹽值**
通過(guò)密碼加鹽从撼,密碼的安全性已經(jīng)提高了不少。但其實(shí)上面的例子存在不少問(wèn)題钧栖。
假設(shè)字符串拼接算法低零、鹽值已外泄,上面的代碼至少存在下面問(wèn)題:
- 短鹽值:需要窮舉的可能性較少拯杠,容易暴力破解掏婶,一般采用長(zhǎng)鹽值來(lái)解決。
- 鹽值固定:類似的潭陪,攻擊者只需要把常用密碼+鹽值的hash值表算出來(lái)雄妥,就完事大吉了最蕾。
短鹽值自不必說(shuō),應(yīng)該避免老厌。對(duì)于為什么不應(yīng)該使用固定鹽值瘟则,這里需要多解釋一下。很多時(shí)候枝秤,我們的鹽值是硬編碼到我們的代碼里的(比如配置文件)醋拧,一旦壞人通過(guò)某種手段獲知了鹽值,那么淀弹,只需要針對(duì)這串固定的鹽值進(jìn)行暴力窮舉就行了丹壕。
比如上面的代碼,當(dāng)你知道鹽值是abc時(shí)薇溃,立刻就能猜到51011af1892f59e74baf61f3d4389092對(duì)應(yīng)的明文密碼是123456菌赖。
那么,該怎么優(yōu)化呢沐序?答案是:隨機(jī)鹽值琉用。
示例代碼如下”∩叮可以看到辕羽,密碼同樣是123456,由于采用了隨機(jī)鹽值垄惧,前后運(yùn)算得出的結(jié)果是不同的刁愿。這樣帶來(lái)的好處是,多個(gè)用戶到逊,同樣的密碼铣口,攻擊者需要進(jìn)行多次運(yùn)算才能夠完全破解。同樣是純數(shù)字3位短鹽值觉壶,隨機(jī)鹽值破解所需的運(yùn)算量脑题,是固定鹽值的1000倍。
var crypto = require('crypto');
function getRandomSalt(){
return Math.random().toString().slice(2, 5);
}
function cryptPwd(password, salt) {
// 密碼“加鹽”
var saltPassword = password + ':' + salt;
console.log('原始密碼:%s', password);
console.log('加鹽后的密碼:%s', saltPassword);
// 加鹽密碼的md5值
var md5 = crypto.createHash('md5');
var result = md5.update(saltPassword).digest('hex');
console.log('加鹽密碼的md5值:%s', result);
}
var password = '123456';
cryptPwd('123456', getRandomSalt());
// 輸出:
// 原始密碼:123456
// 加鹽后的密碼:123456:498
// 加鹽密碼的md5值:af3b7d32cc2a254a6bf1ebdcfd700115
cryptPwd('123456', getRandomSalt());
// 輸出:
// 原始密碼:123456
// 加鹽后的密碼:123456:287
// 加鹽密碼的md5值:65d7dd044c2db64c5e658d947578d759
MD5碰撞
簡(jiǎn)單的說(shuō)铜靶,就是兩段不同的字符串叔遂,經(jīng)過(guò)MD5運(yùn)算后,得出相同的結(jié)果争剿。
直接上例子已艰,參考這里
相關(guān)
如果覺(jué)得文章對(duì)你有點(diǎn)用的話,麻煩拿出手機(jī)蚕苇,這里有一個(gè)你我都有的小福利(每天一次): 打開(kāi)支付寶首頁(yè)搜索“8601304”哩掺,即可領(lǐng)紅包。謝謝支持