我放上盐后盐变了 mysql
Salt as been change after I put it on mysql
我尝试将密码安全地保存在我的数据库中。
我阅读了有关该主题的信息,每个人都建议使用 salt 并使用密码将其保存到。
所以我找到了这个实现:
private static byte[] setSalt() throws NoSuchAlgorithmException {
SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
byte[] salt = new byte[16];
sr.nextBytes(salt);
return salt;
}
然后我尝试将它保存为 MySQL
中的一个字节
public static void test(byte[] salt) throws Exception{
SQLconnect sql = new SQLconnect();
Object[] prepString = {salt, "admin" };
sql.runQuery("UPDATE orhalimi_cl_db.users set Salt = ? where Username = ?",
prepString,ACTION.UPDATE);
}
这里是更新:
preparedStatement = connect.prepareStatement(query);
for (int i = 0; i < prepString.length; i++) {
preparedStatement.setObject(i + 1, prepString[i]);
}
preparedStatement.executeUpdate();
当我从数据库中检索盐并检查 equals
时,再见是不同的。
我在我的数据库中将盐保存为 binary(16)
类型。
这是我从数据库中获取它的方法:
List<HashMap<String, Object>> results;
SQLconnect sql = new SQLconnect();
Object[] prepString = {"Salt", "admin" };
results = sql.runQuery("SELECT ? from orhalimi_cl_db.users where Username = ?",
prepString,ACTION.SELECT);
if (results.isEmpty()) {
System.out.println("empty");
return null;
}
return ((String) results.get(0).get("Salt")).getBytes();
我知道它看起来像我从我的代码中给出了很多不同的部分,
但看起来我在保存或退出 MySQL 时弄乱了字节。所以我提供了所有可能相关的信息。
提前致谢。
答案:
有趣的是,我的问题是我在所有 SQL preparedStatement 上使用了 ?
而不仅仅是值。所以它看起来像 SELECT ? from orhalimi_cl_db.users who Username = ?
变成了 SELECT 'Salt' from orhalimi_cl_db.users where Username = 'admin'
,答案总是盐。
无论如何,我将它转换为十六进制和 base64,现在更容易了
您正在尝试将原始字节值写入 MySQL。由于字节值是 Java 中的带符号的 8 位整数,因此这注定会出错。
您基本上有两个选择:a) 使用 BLOB 数据类型或 b) 将您的字节值编码为 Base64 字符串。
如果是 BLOB 类型(这似乎是您尝试过的),您需要读写二进制安全。这也意味着,您不能简单地将其作为 String 从数据库中读取,然后期望获取的字节与您写入数据库的字节相同。你必须使用二进制流。
我更喜欢第二个选项。它更安全,更简单。特别是因为您需要将密码字符串与盐一起散列。使用 Base64 编码,您可以简单地连接密码和盐,然后计算字符串的哈希值。
编辑:
这里有一个如何生成加盐 SHA512 哈希的示例:
public String getSalt() {
String saltStr = "";
try {
final SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
final byte[] salt = new byte[16];
sr.nextBytes(salt);
saltStr = Base64.getEncoder().encodeToString(salt);
} catch (NoSuchAlgorithmException ignored) { }
return saltStr;
}
public String hashPassword(String password, String salt)
{
try {
final MessageDigest md = MessageDigest.getInstance("SHA-512");
// hash password and salt
md.update(password.getBytes());
md.update(salt.getBytes());
final byte[] hash = md.digest();
// convert byte array to hex string
final StringBuffer sb = new StringBuffer();
for (int i = 0; i < hash.length; ++i) {
sb.append(Integer.toString((hash[i] & 0xff) + 0x100, 16).substring(1));
}
return sb.toString();
} catch (NoSuchAlgorithmException ignored) { return ""; }
}
这样你也可以使用任何其他字符串作为盐。但当然建议使用 getSalt()
.
中的安全随机数生成器
使用此方法的一大优势是您通常不太依赖 Java 的内部字节处理。使用生成的十六进制散列和 Base64 盐字符串,您可以轻松地在 Java 之外重新计算散列值,例如直接在数据库内部。
这是一个 X-Y 问题,真正的问题是 Is it difficult to store password hashes properly?
。答案是肯定的。
我建议您在用户 table 上放置一个 char(60) 列并使用 bcrypt。
你是在故意重新发明轮子吗?也许这是一个学习练习,在这种情况下,go get'em tiger!
我尝试将密码安全地保存在我的数据库中。 我阅读了有关该主题的信息,每个人都建议使用 salt 并使用密码将其保存到。
所以我找到了这个实现:
private static byte[] setSalt() throws NoSuchAlgorithmException {
SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
byte[] salt = new byte[16];
sr.nextBytes(salt);
return salt;
}
然后我尝试将它保存为 MySQL
中的一个字节public static void test(byte[] salt) throws Exception{
SQLconnect sql = new SQLconnect();
Object[] prepString = {salt, "admin" };
sql.runQuery("UPDATE orhalimi_cl_db.users set Salt = ? where Username = ?",
prepString,ACTION.UPDATE);
}
这里是更新:
preparedStatement = connect.prepareStatement(query);
for (int i = 0; i < prepString.length; i++) {
preparedStatement.setObject(i + 1, prepString[i]);
}
preparedStatement.executeUpdate();
当我从数据库中检索盐并检查 equals
时,再见是不同的。
我在我的数据库中将盐保存为 binary(16)
类型。
这是我从数据库中获取它的方法:
List<HashMap<String, Object>> results;
SQLconnect sql = new SQLconnect();
Object[] prepString = {"Salt", "admin" };
results = sql.runQuery("SELECT ? from orhalimi_cl_db.users where Username = ?",
prepString,ACTION.SELECT);
if (results.isEmpty()) {
System.out.println("empty");
return null;
}
return ((String) results.get(0).get("Salt")).getBytes();
我知道它看起来像我从我的代码中给出了很多不同的部分, 但看起来我在保存或退出 MySQL 时弄乱了字节。所以我提供了所有可能相关的信息。
提前致谢。
答案:
有趣的是,我的问题是我在所有 SQL preparedStatement 上使用了 ?
而不仅仅是值。所以它看起来像 SELECT ? from orhalimi_cl_db.users who Username = ?
变成了 SELECT 'Salt' from orhalimi_cl_db.users where Username = 'admin'
,答案总是盐。
无论如何,我将它转换为十六进制和 base64,现在更容易了
您正在尝试将原始字节值写入 MySQL。由于字节值是 Java 中的带符号的 8 位整数,因此这注定会出错。 您基本上有两个选择:a) 使用 BLOB 数据类型或 b) 将您的字节值编码为 Base64 字符串。
如果是 BLOB 类型(这似乎是您尝试过的),您需要读写二进制安全。这也意味着,您不能简单地将其作为 String 从数据库中读取,然后期望获取的字节与您写入数据库的字节相同。你必须使用二进制流。
我更喜欢第二个选项。它更安全,更简单。特别是因为您需要将密码字符串与盐一起散列。使用 Base64 编码,您可以简单地连接密码和盐,然后计算字符串的哈希值。
编辑: 这里有一个如何生成加盐 SHA512 哈希的示例:
public String getSalt() {
String saltStr = "";
try {
final SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
final byte[] salt = new byte[16];
sr.nextBytes(salt);
saltStr = Base64.getEncoder().encodeToString(salt);
} catch (NoSuchAlgorithmException ignored) { }
return saltStr;
}
public String hashPassword(String password, String salt)
{
try {
final MessageDigest md = MessageDigest.getInstance("SHA-512");
// hash password and salt
md.update(password.getBytes());
md.update(salt.getBytes());
final byte[] hash = md.digest();
// convert byte array to hex string
final StringBuffer sb = new StringBuffer();
for (int i = 0; i < hash.length; ++i) {
sb.append(Integer.toString((hash[i] & 0xff) + 0x100, 16).substring(1));
}
return sb.toString();
} catch (NoSuchAlgorithmException ignored) { return ""; }
}
这样你也可以使用任何其他字符串作为盐。但当然建议使用 getSalt()
.
使用此方法的一大优势是您通常不太依赖 Java 的内部字节处理。使用生成的十六进制散列和 Base64 盐字符串,您可以轻松地在 Java 之外重新计算散列值,例如直接在数据库内部。
这是一个 X-Y 问题,真正的问题是 Is it difficult to store password hashes properly?
。答案是肯定的。
我建议您在用户 table 上放置一个 char(60) 列并使用 bcrypt。
你是在故意重新发明轮子吗?也许这是一个学习练习,在这种情况下,go get'em tiger!