Web系统的密码加密问题(摘要算法)

思路

 

盐值+MD5摘要算法

1.为了防止字典破解(常用字符),先生成一个长度16位(位数最好和摘要算法的结果长度一致)的随机(安全随机数)byte数组作为盐值,通过Base64编码之后,将其和原密码按规则组合,保证进行摘要运算前的明文是无规律的。

2.使用MD5摘要算法对明文进行运算得到一个长度16位的摘要byte数组,通过Base64编码后,得到一个24位的密文密码。

 

实现

 

工具类

 1 public class PasswordProcessor {
 2     public static void main(String[] args) {
 3 
 4     }
 5     public static byte[] makeSalt() {
 6         SecureRandom secureRandom = null;
 7         try {
 8             secureRandom = SecureRandom.getInstanceStrong(); // 尝试获取高强度安全随机数生成器
 9         } catch (NoSuchAlgorithmException e) {
10             secureRandom = new SecureRandom(); // 获取普通的安全随机数生成器
11         }
12         byte[] saltBuffer = new byte[16];
13         secureRandom.nextBytes(saltBuffer);
14         return saltBuffer;
15     }
16 
17     public static byte[] getDigest(String str) {
18         MessageDigest md = null;
19         try {
20             md = MessageDigest.getInstance("md5");
21         } catch (NoSuchAlgorithmException e) {
22             e.printStackTrace();
23         }
24         byte[] digest = md.digest(str.getBytes());
25         return digest;
26     }
27 }

 

注册

进行上述步骤,将盐值和密文密码分开存放。

 1 public boolean signUpJudge(User user) {
 2         Base64.Encoder encoder = Base64.getEncoder();
 3         byte[] salt = PasswordProcessor.makeSalt();
 4         String saltStr = encoder.encodeToString(salt); // 获取随机盐值
 5         StringBuilder sb = new StringBuilder();
 6         sb.append(user.getPassword()).append(saltStr);
 7         byte[] password = PasswordProcessor.getDigest(sb.toString());
 8         user.setPassword(encoder.encodeToString(password)); // 获取密文密码
 9         user.setProfile("../images/profile/default.png");
10         int rs = userDao.insertUser(user);
11         int rs2 = saltDao.insertSalt(user.getId(), saltStr);
12         if (rs == 1 && rs2 == 1) return true;
13         else return false;
14     }

 

登录

将数据库中的盐值取出,和用户输入的密码按规则组合,进行摘要算法和Base64编码,得到密文密码,判断是否与数据库中的密文密码相等。

 1 public boolean loginJudge(User user) {
 2         String salt = saltDao.selectSaltById(user.getId()); // 从数据库中查出对应盐值
 3         if (salt == null) return false; // 若没有该id 说明用户不存在
 4         StringBuilder sb = new StringBuilder();
 5         sb.append(user.getPassword()).append(salt);
 6         byte[] password = PasswordProcessor.getDigest(sb.toString());
 7         Base64.Encoder encoder = Base64.getEncoder();
 8         user.setPassword(encoder.encodeToString(password)); // 获取密文密码
 9         int rs = userDao.selectUserByIdAndPassword(user);
10         if (rs == 0) return false;
11         else return true;
12     }

 

关于摘要算法的选择

 

签名认证

山东大学的王小云教授发布算法可以轻易构造MD5碰撞实例,此后,有国外学者在此算法基础上,提出了更进一步的MD5前缀碰撞构造算法"chosen prefix collision",而SHA1的碰撞实例也被谷歌成功构造。因此在数字签名方面,对于数据完整性验证,应使用SHA256或更强的算法。

 

密码验证

上述碰撞实例对密码加密并没有实质性的影响,加密需要考虑的一个问题在于,任何加密都无法避开暴力破解,那如何尽可能地提高暴力破解的难度?

一个合理的思路是:提高加密的时间成本。

基于这种思路,可以使用bcrypt算法,这种算法的优点是计算速度慢,还可以通过参数调节速度。对于登录验证,只需要通过多次调试,把速度控制在500ms左右,不会对用户影响造成体验,却能很大程度提高暴力破解的时间成本。

posted @ 2020-09-06 23:15  昆梧  阅读(396)  评论(0)    收藏  举报