课程名称:web前端架构师
课程章节:第16周 第三章 加密方式选型以及返回结果的特殊处理
主讲老师:张轩
课程内容: 接口参数验证功能和错误信息处理
加密方式选型
几种加密方式
明文保存 plaintext - 坚决不能使用
md5 hash 保存 - 碰撞,彩虹表
MD5('123') = 202CB962AC59075B964B07152D234B70
username: viking
password: 202CB962AC59075B964B07152D234B70
md5 hash + salt(盐)保存
盐(Salt),在密码学中,是指在hash之前将明文内容(例如:密码)的任意固定位置插入特定的字符串。
MD5('123' + '1ck12b13k1jmjxrg1h0129h2lj') = '6c22ef52be70e11b6f3bcf0f672c96ce'
username: viking
password: 6c22ef52be70e11b6f3bcf0f672c96ce
salt: 1ck12b13k1jmjxrg1h0129h2lj
bcrypt
一种加盐的单向Hash,不可逆的加密算法,同一种明文(plaintext),每次加密后的密文都不一样,而且不可反向破解生成明文,破解难度很大。而且生成密码时间也比较长
bcrypt('123') = $2b$10$69SrwAoAUNC5F.gtLEvrNON6VQ5EX89vNqLEqU655Oy9PeT
md5(123 + 69SrwAoAUNC5F) = abc
md5(xyz + 69SrwAoAUNC5F) = efg
username: viking
password: $2b$10$69SrwAoAUNC5F.gtLEvrNON6VQ5EX89vNqLEqU655Oy9PeT
对比几种方式,bcrypt 最安全,所以选用 bcrypt
将 bcrypt 添加的应用
bcrypt 有现成的 egg.js 插件 egg-bcrypt,也可以使用 bcrypt.js
实现用户注册密码加密
课程中使用了 egg-bcrypt ,我这里就使用 bcrypt.js 来实现下
bcrypt 的使用
npm i bcryptjs
创建hash
import bcrypt from 'bcryptjs';
bcrypt.genSalt(10, function(err, salt) {
bcrypt.hash('B4c0/\/', salt, function(err, hash) {
});
});
校验密码
bcrypt.compare("B4c0/\/", hash, function(err, res) {
// res === true
});
编写密码加密与比对
加密
...
public genHash(pwd: string): Promise<string> {
return new Promise((resolve, reject) => {
bcrypt.genSalt(10, function(err, salt) {
if (err) return reject(err);
bcrypt.hash(pwd, salt, function(err, hash) {
if (err) return reject(err);
resolve(hash);
});
});
});
}
...
比对密码
public compare(pwd: string, hash: string):Promise<boolean> {
return new Promise((resolve, reject) => {
bcrypt.compare(pwd, hash, function(err, res) {
err ? reject(err) : resolve(res);
});
});
}
创建用户时加密密码
const hash = await this.genHash(password);
const user: Partial<User> = {
username,
password: hash,
email: username,
};
登录时,比对密码
public async signin() {
const { ctx, service, app } = this;
const errors = app.validator.validate(userRules, ctx.request.body);
// 参数是否输入争取
if (errors && errors.length) {
return ctx.helper.error({ ctx, errType: 'userValidateFail', err: errors });
}
const { username, password } = ctx.request.body;
// 登录 username 是否存在
const user = await service.user.findByUsername(username);
if (!user) {
return ctx.helper.error({ ctx, errType: 'signinValidateFail', err: errors });
}
// 比对密码
const verifyPwd = await service.user.compare(password, user.password);
if (!verifyPwd) {
return ctx.helper.error({ ctx, errType: 'signinValidateFail', err: errors });
}
ctx.helper.success({
ctx,
res: user,
msg: '登录成功',
});
}
就这样就完成了用户的创建密码加密和登录密码比对