本文描述了本人,对于数据库中如何保存密码的认识过程。从最简单的明文保存到密码加盐保存,下面与大家分享下:
第一阶段
最开始接触web
开发时,对于用户表的密码基本是明文保存,如:
username | password
---------|----------
zp1996 |123456
zpy |123456789
这种方式可以说很不安全,一旦数据库泄漏,那么所以得用户信息就会被泄漏。之前,国内普遍采用这种方式,造成了很多的事故,如csdn
600万用户信息泄漏、12306
用户信息泄漏等。
第二阶段
本人大学做过的所有的项目基本采用的都是这种方式来保存用户密码,就是对密码进行md5
加密,在php
中md5
即可,在node
中利用crypto
模块就好:
const encrypt = (text) => {
return crypto.createHash("md5").update(String(text)).digest("hex");
};
作为初学者的我,认为这种方式是很安全的,因为md5
不可逆(指攻击者不能从哈希值h(x)中逆推出x)而且碰撞几率低(指攻击值不能找到两个值x、x’具有相同的哈希值);然而这种方式也是不安全的,只要枚举出所有的常用密码,做成一个索引表,就可以推出来原始密码,这张索引表也被叫做“彩虹表”(之前csdn
600万用户明文密码就是一个很好的素材)。
第三阶段
这种方式是在实习中学习到的,也就是对密码来进行加盐。
什么是加盐?
在密码学中,是指通过在密码任意固定位置插入特定的字符串,让散列后的结果和使用原始密码的散列结果不相符,这种过程称之为“加盐”。
加盐很好理解,就是给原始密码加上特定的字符串,这样给攻击者增加攻击的成本,加盐的关键在于如何选择盐:
固定字符串
采用固定的字符串作为盐,如下面这样:
const encrypt = (text) => {
text = text + 'zp';
return crypto.createHash("md5").update(text).digest("hex");
};
这种加盐方式与多进行几次md5
一样的,没有任何意义,攻击者都可以拿到数据库,难道拿不到源代码吗,根据源代码攻击者很轻松的就可以构造新的彩虹表出来逆推密码。
随机字符串
盐一般要求是固定长度的随机字符串,且每个用户的盐不同,比如10位,数据库可以这样存储:
username | password |salt
---------|---------—------------------------|----------
zp1996 |2636fd8789595482abf3423833901f6e |63UrCwJhTH
zpy |659ec972c3ed72d04fac7a2147b5827b |84GljVnhDT
采用的加密方式为:
md5(md5(password) + salt)
- 1
将其转化为node
代码:
/*
* 10位盐
* 时间戳(2)+随机字母(8)
*/
const salt = () => {
var time = Date.now() % 100,
str = '';
time = time === 0 ? '00' : String(time);
for (let i = 0; i < 8; i++) {
const base = Math.random() < 0.5 ? 65 : 97;
str += String.fromCharCode(
base +
Math.floor(
Math.random() * 26
)
);
}
return time + str;
};
const md5 = (text) => {
return crypto.createHash("md5").update(String(text)).digest("hex");
};
const encrypt = (password) => {
return md5(md5(password) + salt());
};
写在最后
以随机字符串作为盐对密码进行加盐仅仅是增加破解密码的难度,假如目前有30w的用户数据,那么就会有30w个盐,利用600w的索引表去比对的话,需要创造出30w*600w的数据来一一比对,这样会增加攻击者的成本。以上内容,如有错误,欢迎大家指出。