java - Java/SpringBoot:验证加盐哈希返回错误哈希
问题描述
所以,我目前正在学习 SpringBoot,现在我正在尝试将密码与其他用户数据一起存储在数据库(MySql)中。为了安全起见,我使用加盐哈希值进行存储。生成这些哈希并将它们存储在数据库中工作正常,但是当我尝试通过获取盐和密码来验证密码时,我得到了不同的哈希,因此结果错误。
下面是我的代码。
第一个:User
我开始验证的类
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
private long uID;
@NotNull
private String nname;
@NotNull
private String vname;
private String email;
private String telnr;
@Embedded
private Address address;
@NotNull
private boolean isAdmin;
private String hash;
// Default Constructor
public User() {
}
// Constructor
public User(String name, String vname, String email, String telnr, Address address, boolean isAdmin,
String password) throws NoSuchAlgorithmException {
HashHelper hashHelper = new HashHelper();
this.nname = name;
this.vname = vname;
this.email = email;
this.telnr = telnr;
this.address = address;
this.isAdmin = isAdmin;
this.hash = hashHelper.createHash(password);
}
public boolean validateHash(String password) {
HashHelper hashHelper = new HashHelper();
// Get the used Salt
String[] parts = this.hash.split(":");
byte[] salt = parts[0].getBytes();
// Create Hash with old salt
String newHash = hashHelper.getHash(password, salt);
if (parts[1] == newHash) {
return true;
}
return false;
}
其次,HashHelper
我处理与散列有关的所有事情的班级。createHash
每当存储新密码(因此是新盐)并getHash
使用特定盐进行验证时,我都会使用它。
public class HashHelper {
public HashHelper() {
}
public byte[] getSalt() throws NoSuchAlgorithmException {
SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
byte[] salt = new byte[16];
sr.nextBytes(salt);
return salt;
}
// Create Salt and Hash and store them, seperated by :
public String createHash(String password) throws NoSuchAlgorithmException {
String hash = null;
byte[] salts = getSalt();
try {
MessageDigest md = MessageDigest.getInstance("SHA-256");
md.update(salts);
byte[] bytes = md.digest(password.getBytes());
StringBuilder sb = new StringBuilder();
for (int i = 0; i < bytes.length; i++) {
sb.append(Integer.toString((bytes[i] & 0xff) + 0x100, 16).substring(1));
}
hash=salts.toString() + ":" + sb.toString();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
System.out.println("Hash: " + hash);
return hash;
}
public String getHash(String password, byte[] salt) {
String hash = "";
try {
MessageDigest md = MessageDigest.getInstance("SHA-256");
md.update(salt);
byte[] bytes = md.digest(password.getBytes());
StringBuilder sb = new StringBuilder();
for (int i = 0; i < bytes.length; i++) {
sb.append(Integer.toString((bytes[i] & 0xff) + 0x100, 16).substring(1));
}
hash = sb.toString();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return hash;
}
}
验证调用在 CommandLineRunner 中设置,仅用于测试,如下所示:
Optional<User> user = userRepository.findById((long)10);
if (user.get().validateHash("Password")) {
System.out.println("Correct Password");
}
else {
System.out.println("Wrong password");
}
我认为这与getBytes()
andtoString()
方法有关,因为byte[] salt
当我尝试验证它时似乎长度更短(大约 11-12 个字节而不是 16 个字节),但我不知道为什么。任何帮助将不胜感激!
解决方案
你的问题没有实际意义,因为你不应该使用这个算法来散列密码,因为它不安全。即使您没有保护任何重要的东西,用户也可能在多个地方使用相同的密码,当攻击者破解您的不安全密码表时,他们将能够在其他地方使用其中的许多密码。
使用 Argon2 或至少 PBKDF2 对密码进行哈希处理,至少进行 10,000 轮哈希处理。
您在这里遇到问题的原因是您没有存储用于散列密码的盐。没有它,您将永远无法计算相同的哈希值。问题salts.toString()
出在createHash()
方法上:
hash=salts.toString() + ":" + sb.toString();
调用toString()
abyte[]
不会告诉您有关数组内容的任何信息。这就是为什么您不厌其烦地将摘要的结果 , 转换bytes
为十六进制的原因。你应该做一些类似于盐的事情。
同样,调用getBytes()
字符串只会使用您平台的默认编码对字符串进行编码。那不是你想要的。
确保equals()
在比较String
实例时使用他们的方法。==
操作员只会告诉您它们是否是相同的实例。
在存储字节数组时,您仍然需要使用良好的哈希算法,我建议使用 base-64,因为在 中对它有很好的支持,java.util.Base64
它会产生更紧凑的数组编码。
推荐阅读
- parent-child - 如何在作为可放置元素的子元素的可拖动元素上拖动元素?
- ansible - Ansible - 从特定角色开始
- c - 使用 pro*c 从 C 程序连接 oracle 数据库
- linux - 在没有属性文件的情况下执行 SonarScanner 时如何指定项目版本
- python - 服务器重新加载后python电报机器人停止工作
- spring - 从 Cloud Foundry java-buildpack-auto-reconfiguration 禁用特定的 bean 类型
- robotframework - 关键字:Selenium2Library.Wait until Element Is Visible' 预期 1 到 3 个参数,得到 4
- javascript - 谁能告诉我为什么变量“item”的值是未定义的?
- vbscript - 我有一个 HTAFile 用作安装应用程序的菜单。一切正常,直到我使用 VBS Edit 从 HTAFile 创建一个 exe
- c# - 比较两个列表并找出不匹配的地方