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左右,不会对用户影响造成体验,却能很大程度提高暴力破解的时间成本。

浙公网安备 33010602011771号