我正在使用此代码加密和解密密码
public class SecureDigester
{
private static final char digits[] =
{ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E',
'F' };
private static String byteArrayToHexString(byte[] b)
{
StringBuffer hexString = new StringBuffer(b.length);
for (int i = 0; i < b.length; i++)
{
hexString.append(digits[(b[i] & 0xF0) >> 4]);
hexString.append(digits[b[i] & 0x0F]);
}
return hexString.toString();
}
public static String digest(String plaintext)
{
try
{
MessageDigest md = MessageDigest.getInstance("SHA");
md.update(plaintext.getBytes("UTF-8"));
byte[] mdBytes = md.digest();
String hashString = byteArrayToHexString(mdBytes);
return hashString;
} catch (Exception e)
{
throw new RuntimeException(e);
}
}
}
在我的登录信息中,我使用此代码解密密码:
String passwordDigest = SecureDigester.digest(password);
if (!user.getPassword().equals(passwordDigest))
{
// authentication failed: bad password
}
现在我有了忘记密码.jsp页面,该页面将用户的用户名和密码发送到他/她指定的电子邮件中。但是当我使用下面的代码时,我收到的加密密码也与我数据库中的加密密码不同。
String Email = req.getParameter("email");
User userItem = new UserDAO().findEmail(Email);
SendMailSSL sendEmail = new SendMailSSL();
String password = userItem.getPassword();
String EPassword = SecureDigester.digest(password);
sendEmail.send(userItem.getUsername(), EPassword, userItem.getEmail());
如何解决这个问题?
答案 0 :(得分:4)
像SHA和MD5这样的加密哈希是单向哈希。无法反转单向散列。您可以从任何明文生成加密哈希,但是您无法确定仅给出哈希值的原始明文。
您的“解密”代码实际上并未解密SHA哈希值。相反,它会散列用户刚输入的密码,并将该散列与之前存储的散列进行比较。如果哈希匹配则表示密码匹配。
像这样散列密码是一个很好的安全方案,但其中一个结果就是你无法通过电子邮件向用户发送密码:你没有他们的密码!你只有不可逆转的哈希。这就是为什么现在具有良好安全性的网站如果忘记密码,就不会通过电子邮件向您发送原始密码。相反,他们提供了一些重置密码的方法。如果您遇到 能够通过电子邮件向您发送密码的网站,那就是一个巨大的红旗!
答案 1 :(得分:1)
看起来您将密码作为SHA1哈希值存储在数据库中。这很棒,你应该这样做(绝对是最好的做法)。使用SHA1(或任何其他单向散列)的“缺点”是您无法将散列“解密”回原始明文。这意味着以下代码不起作用。
String Email = req.getParameter("email");
User userItem = new UserDAO().findEmail(Email);
SendMailSSL sendEmail = new SendMailSSL();
String password = userItem.getPassword(); // the userItem returns an SHA1 hash
String EPassword = SecureDigester.digest(password); // this just rehashes the hash
sendEmail.send(userItem.getUsername(), EPassword, userItem.getEmail());
问题不在于此代码与方法一样多。由于您无法从SHA1哈希(这是一个好的事物)中恢复用户的明文密码,因此您需要向用户发送一个链接以重置其密码而不是电子邮件包含他们的密码。电子邮件是一个不安全的渠道,密码(除了必须更改的初始密码)不应该通过电子邮件发送。
这个问题有两种方法。