【发布时间】:2021-03-03 01:00:57
【问题描述】:
当用户使用我的 java 应用程序注册时,我已经构建了一个函数来散列用户密码。我不确定我应该如何尝试验证他们的登录,因为存储的密码将被散列。
我尝试过创建一个函数,该函数获取输入的密码并对其进行哈希处理,然后将哈希值与数据库中的哈希值进行比较,但这不起作用,因为每次在密码(字符串)上运行哈希函数时结果永远不一样。我不确定如何在登录时验证用户密码。下面我提供了:
- 登录按钮代码
- 使用盐函数生成安全密码
- 验证功能
登录按钮代码:
try {
// Get password from database and verify login
String slt = passwordUtils.getSalt(100);
Connection con = connectDB.getConnectionUser();
Statement stmt = null;
String sql = "SELECT * FROM USER where userEmail=?";
PreparedStatement pst = con.prepareStatement(sql);
pst.setString(1, userEmail.getText());
ResultSet rs = pst.executeQuery();
String fromDatabase = rs.getString(3); //get the password stored in database (hashed version)
String enteredPassword = String.valueOf(userPassword.getPassword()); //get entered password
if(rs.next()){
if(passwordUtils.verifyUserPassword(enteredPassword, fromDatabase, slt)){
JOptionPane.showMessageDialog(null, "Login details are correct. Welcome!");
con.close();
} else {
JOptionPane.showMessageDialog(null, "Invalid Log in details, try again.");
con.close();
}
}
} catch (SQLException ex) {
Logger.getLogger(Login.class.getName()).log(Level.SEVERE, null, ex);
}
生成安全密码功能
public static String generateSecurePassword(String password, String salt){
String returnValue = null;
System.out.println("password supplied is: " + password + "salt added: " + salt);
System.out.println("");
byte[] securePassword = hash(password.toCharArray(), salt.getBytes());
System.out.println("");
System.out.println("secure pwd byte[]: " + securePassword);
System.out.println("");
returnValue = Base64.getEncoder().encodeToString(securePassword);
System.out.println("");
System.out.println("secure pwd converted " + returnValue);
return returnValue;
}
验证登录功能
public static boolean verifyUserPassword(String providedPassword, String securedPassword, String salt){
boolean returnValue = false;
// generate new secure password with same salt
String newSecurePassword = generateSecurePassword(providedPassword, salt); //generate secure password using salt
//check to see if both passwords are the same
returnValue = newSecurePassword.equalsIgnoreCase(securedPassword);
System.out.println("Hashed password: " + securedPassword);
System.out.println("Verify hash: "+ newSecurePassword);
return returnValue;
}
加盐功能
public static String getSalt(int length){;
StringBuilder returnValue = new StringBuilder(length);
for(int i = 0; i < length; i++){
returnValue.append(ALPHABET.charAt(RANDOM.nextInt(ALPHABET.length())));
}
System.out.println("final salt generated: " + returnValue);
return new String(returnValue);
}
散列函数:
public static byte[] hash(char[] password, byte[] salt){
PBEKeySpec spec = new PBEKeySpec(password, salt, ITERATIONS, KEY_LENGTH);
Arrays.fill(password, Character.MIN_VALUE);
try{
SecretKeyFactory skf = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA512");
System.out.println("skf return to secure password call: " + skf.generateSecret(spec).getEncoded());
return skf.generateSecret(spec).getEncoded();
} catch (NoSuchAlgorithmException | InvalidKeySpecException e){
throw new AssertionError("Error while hashing a password: " + e.getMessage(), e);
} finally {
spec.clearPassword();
System.gc();
}
}
【问题讨论】:
-
passwordUtils.getSalt(100);应该做什么?每当设置新密码时,盐应该计算一次,然后盐应该与加盐+散列的密码一起存储并与它一起检索。然后,您需要使用相同的盐与用户刚刚输入的密码相结合,并对结果进行哈希处理,然后比较结果。现在你要么每次都创建一个新的盐,这根本行不通,要么你为所有用户使用相同的盐,这打败了大部分盐。 -
抱歉,我在帖子中添加了 getSalt() 函数。我调用 passwordUtils.getSalt(100) 并将其存储为 String slt 因为我需要将它传递给我的 verifyUserPassword 方法
-
然后再次阅读我评论的第一部分,也许会阅读盐应该是什么。当用户尝试登录时,您无法创建新盐,您需要在用户设置密码时生成盐,然后存储该盐并在该用户的所有未来散列操作中使用它。
-
我明白你的意思。我不太明白如何输入输入的密码,例如“密码”,然后将其验证为数据库中的哈希版本
标签: java authentication salt