写点什么

编程常用的加密方式

用户头像
皮蛋
关注
发布于: 2021 年 01 月 03 日

1. 明文保存

比如用户设置的密码是“123456”,直接将“123456”保存在数据库中,这种是最简单的保存方式,也是最不安全的方式。但实际上不少互联网公司,都可能采取的是这种方式。

2. 对称加密算法

使用对称加密算法来保存,比如 3DES、AES 等算法,使用这种方式加密是可以通过解密来还原出原始密码的,当然前提条件是需要获取到密钥。不过既然大量的用户信息已经泄露了,密钥很可能也会泄露,当然可以将一般数据和密钥分开存储、分开管理,但要完全保护好密钥也是一件非常复杂的事情,所以这种方式并不是很好的方式。


3. 非对称加密算法

RSA、DSA 等非对称加密算法需要公钥和私钥。公钥和私钥是一对,用公钥对数据进行加密,只有用对应的私钥才能解密。非对称加密与对称加密相比,其安全性更好。一对秘钥,一个用来加密,一个用来解密,而且公钥是公开的,秘钥是自己保存的


4.单向散列加密

包括 MD5、SHA1、SHA2、SHA256、PBKDF2...等单向 HASH 算法

使用 MD5、SHA1 等单向 HASH 算法保护密码,无法通过计算还原出原始密码,而且实现比较简单,因此很多互联网公司都采用这种方式保存用户密码,曾经这种方式也是比较安全的方式,但随着彩虹表技术的兴起,可以建立彩虹表进行查表破解,目前这种方式已经很不安全了。


使用 SHA2 等算法是特殊的单向 HASH 算法,是在单向 HASH 算法基础上进行了加盐、多次 HASH 等扩展,这些方式可以在一定程度上增加破解难度,对于加了“固定盐”的 HASH 算法,需要保护“盐”不能泄露,这就会遇到“保护对称密钥”一样的问题,一旦“盐”泄露,根据“盐”重新建立彩虹表可以进行破解,对于多次 HASH,也只是增加了破解的时间,并没有本质上的提升。


PBKDF2 算法,该算法原理大致相当于在 HASH 算法基础上增加随机盐,并进行多次 HASH 运算,随机盐使得彩虹表的建表难度大幅增加,而多次 HASH 也使得建表和破解的难度都大幅增加。使用 PBKDF2 算法时,HASH 算法一般选用 sha1 或者 sha256,随机盐的长度一般不能少于 8 字节,HASH 次数至少也要 1000 次,这样安全性才足够高。一次密码验证过程进行 1000 次 HASH 运算,对服务器来说可能只需要 1ms,但对于破解者来说计算成本增加了 1000 倍,而至少 8 字节随机盐,更是把建表难度提升了 N 个数量级,使得大批量的破解密码几乎不可行,该算法也是美国国家标准与技术研究院推荐使用的算法。

下表对比了各个算法的特性:

总结

采用 PBKDF2 等算法可以有效抵御彩虹表攻击,即使数据泄露,最关键的“用户密码”仍然可以得到有效的保护,黑客无法大批量破解用户密码,从而切断撞库扫号的根源。


JAVA 实现自带 rt.jar 实现用户密码验证操作:

package com.sd.power.security.admin;private Sha256PasswordEncoder encoder = new Sha256PasswordEncoder();
public RestResponse<User> checkPW(String username, String password) { User user = userBiz.getUserByUsername(username); if(null == user){ return new ObjectRestResponse().error(AdminCommonConstant.USER_MOBILE_NOT_EXIST,AdminCommonConstant.USER_MOBILE_NOT_EXIST_M); } if (StringUtils.isBlank(user.getPassword()) || !encoder.matches(password, user.getPassword())) { return new ObjectRestResponse().error(AdminCommonConstant.USER_PW_ERROR,AdminCommonConstant.USER_PW_ERROR_M); } return new RestResponse().data(user); }
复制代码


package com.sd.power.security.util;import org.apache.commons.codec.binary.Base64;import org.springframework.security.crypto.password.PasswordEncoder;import java.security.MessageDigest;
public class Sha256PasswordEncoder implements PasswordEncoder { @Override public String encode(CharSequence charSequence) { try { MessageDigest md = MessageDigest.getInstance("SHA-256"); byte digest[] = md.digest(charSequence.toString().getBytes("UTF-8")); return new String(Base64.encodeBase64(digest)); } catch (Exception e) { return null; } }
@Override public boolean matches(CharSequence charSequence, String s) { return this.encode(charSequence.toString()).equals(s); }}
复制代码


参照:

https://blog.csdn.net/xiaokui_wingfly/article/details/38045871?utm_source=tuicool&utm_medium=referral

https://cloud.tencent.com/developer/article/1186925


用户头像

皮蛋

关注

趁着年轻把想实现的实现掉 2019.12.19 加入

又懒又笨

评论

发布
暂无评论
编程常用的加密方式