Hashed passwords updated through JDBC become corrupt. (More of encoding problem than hashing)
I've tried the following with MySQL UTF-8 and Latin-1, to no avail.
I hash my passwords (in this case toSecurify) using SHA-1 like so:
if(toSecurify == null) {
throw new Exception("toSecurifyString must not be null");
}
try {
MessageDigest messageDigest = MessageDigest.getInstance("SHA-1");
byte[] sha1HashBytes = new byte[40];
messageDigest.update(toSecurify.getBytes(), 0, toSecurify.length());
sha1HashBytes = messageDigest.digest();
return new String(sha1HashBytes, "UTF-8");
} catch(NoSuchAlgorithmException nsae) {
throw new Exception("Hash algorithm not supported.");
} catch(UnsupportedEncodingException uee) {
throw new Exception("Encoding not supported.");
}
Then I store this in the mysql database password column.
Now here's the tricky part I can query the db kind of like: Is there any record with
username=<insertUserName> and password = thatHashFunctionUpThere(<insertPassword>);
This works great.
But now, updating records looks something like this:
String userName = someJdbcStuffToGetUsername();
String password = someJdbcStuffToGetPassword();
update(userName, password);
The password has now changed! Thi开发者_运维问答s corrupts the passwords. It's like on the way out (when querying for it) it gets corrupted, but never on the way in. I say this because inserts and queries work great, but when I get the value out then set it again, it corrupts it, so it must be on the way out.
Does anyone have any thoughts? Where on the way out should I look for encoding issues?
Thanks in advance guys!
There's a flaw in your code.
return new String(sha1HashBytes, "UTF-8");
You shouldn't be treating the bytes as characters. You should in fact convert every byte to a 2-character hexstring. E.g.
StringBuilder hex = new StringBuilder(sha1HashBytes.length * 2);
for (byte b : sha1HashBytes) {
if ((b & 0xff) < 0x10) hex.append("0");
hex.append(Integer.toHexString(b & 0xff));
}
return hex.toString();
But, better is to just use MySQL's own SHA1()
function. On INSERT
do:
String sql = "INSERT INTO user (username, password) VALUES (?, SHA1(?))";
// ...
preparedStatement = connection.prepareStatement(sql);
preparedStatement.setString(username);
preparedStatement.setString(password); // This one should be unhashed!!
int affectedRows = preparedStatement.executeUpdate();
// ...
and on UPDATE
:
String sql = "UPDATE user SET username = ?, password = SHA1(?) WHERE id = ?";
// ...
preparedStatement = connection.prepareStatement(sql);
preparedStatement.setString(username);
preparedStatement.setString(password); // This one should be unhashed!!
preparedStatement.setLong(id);
int affectedRows = preparedStatement.executeUpdate();
// ...
and on SELECT
:
String sql = "SELECT * FROM user WHERE username = ? AND password = SHA1(?)";
// ...
preparedStatement = connection.prepareStatement(sql);
preparedStatement.setString(username);
preparedStatement.setString(password); // This one should be unhashed!!
resultSet = preparedStatement.executeQuery();
// ...
See also:
- Using prepared statements
精彩评论