开发者

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
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜