我正在尝试保护我正在构建的web应用程序的密码。我对密码学还很陌生。我使用Java和Sha-1 Hash将密码存储在数据库中。
在对这个问题进行了一些研究之后,使用盐似乎是对密码进行散列的最好方法,但当然,盐必须与密码一起存储。
在我的例子中,我在数据库中使用了一个新的列作为盐,我不知道这是不是正确的方法。如果有人窃取了我的数据库,用哈希和盐就能读取密码吗?在散列和盐之间加一个分隔符并存储在一起是不是更好?在这种情况下,为了检查密码的有效性,我必须解析字符串。我只是想知道你的意见和最佳实践,可以适用于这里。
非常感谢您的提前!
@Entity
@Table(name="USERS")
public class User implements BasePersistentEntity<Long> {
/**
*
*/
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
@Column(name="ID")
private Long id;
@Column(name="EMAIL",nullable=false,length=50,insertable=true,updatable=true)
private String email;
@Column(name="PASSWORD",nullable=false,length=40,insertable=true,updatable=true)
private String password;
@Column(name="SALT",nullable=false,length=40,insertable=true,updatable=true)
private String passwordSalt;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email=email;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
if (password.equals(this.password))
{
return;
}
if (passwordSalt == null || passwordSalt.equals(""))
{
passwordSalt = RandomStringUtils.randomAscii(20);
}
this.password = DigestUtils.sha1Hex(password + passwordSalt);
}
/**
* Check if a given password is correct.
*
* @param givenPassword
* @return True is correct, else false.
*/
public boolean checkPassword(String givenPassword)
{
return (password.equals(DigestUtils.sha1Hex(givenPassword + passwordSalt)));
}
public String getPasswordSalt() {
return passwordSalt;
}
public void setPasswordSalt(String passwordSalt) {
this.passwordSalt = passwordSalt;
}
}发布于 2015-02-10 07:05:03
盐是如何存储的对方案的安全性无关紧要。盐和散列都可以以明文形式存储。
该盐可用于防止彩虹表攻击,以及为相同的密码创建不同的散列。
然而,您缺少的是某种工作因子或迭代计数。这是由密码密钥导出函数提供的,例如PBKDF2 (包含在Java中)或bcrypt。这将提供一些针对暴力破解攻击的额外保护(尝试所有类型的密码,并查看它们是否匹配)。这将增加一些安全性,因为密码通常缺乏足够的熵。
可以在服务器应用程序中存储可与盐组合的静态“胡椒”。如果只有数据被盗,这可能会增加一些安全性。
不带胡椒粉的例子:
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
public class PBKDF2ForPasswordHash {
private static final String PBKDF_ALGORITHM = "PBKDF2WithHmacSHA1";
private static final int ITERATION_COUNT = 10_000;
// should be less than the size of the underlying hash
private static final int PASSWORD_HASH_SIZE_BYTES = 16;
private static final int SALT_SIZE_BYTES = 16;
public static byte[] generateRandomSalt(final int saltSizeBytes) {
final SecureRandom rng = new SecureRandom();
final byte[] salt = new byte[saltSizeBytes];
rng.nextBytes(salt);
return salt;
}
public static byte[] generatePasswordHash(final char[] password,
final byte[] salt) {
SecretKeyFactory f;
try {
f = SecretKeyFactory.getInstance(PBKDF_ALGORITHM);
} catch (final NoSuchAlgorithmException e) {
throw new IllegalStateException("PBKDF algorithm "
+ PBKDF_ALGORITHM + " not available", e);
}
final KeySpec ks = new PBEKeySpec(password, salt, ITERATION_COUNT,
PASSWORD_HASH_SIZE_BYTES * Byte.SIZE);
SecretKey s;
try {
s = f.generateSecret(ks);
} catch (final InvalidKeySpecException e) {
throw new IllegalArgumentException(
"PBEKeySpec should always be valid for " + PBKDF_ALGORITHM,
e);
}
return s.getEncoded();
}
public static final String toHex(final byte[] data) {
final StringBuilder sb = new StringBuilder(data.length * 2);
for (int i = 0; i < data.length; i++) {
sb.append(String.format("%02x", data[i]));
}
return sb.toString();
}
public static void main(final String[] args) throws Exception {
final char[] password = { 'o', 'w', 'l' };
final byte[] salt = generateRandomSalt(SALT_SIZE_BYTES);
System.out.println(toHex(salt));
final byte[] hash = generatePasswordHash(password, salt);
System.out.println(toHex(hash));
}
}发布于 2015-02-10 07:10:45
将盐以明文形式存储在散列旁边是很好的,因为密码是安全的(如果你在应用程序上小心处理它--不要记录它等等)。盐的要点是为每个用户的散列有一个唯一的输入,所以你不能只使用彩虹表或猜测密码(例如,许多用户有相同的散列,然后他们使用相同的密码。我曾经因为一个差劲的md5应用程序而熟记"password01“的wep散列)
要找出如何正确地做到这一点,请参考这个:https://crypto.stackexchange.com/questions/760/webapp-password-storage-salting-a-hash-vs-multiple-hashes,因为你需要确保你不会受到像计时攻击这样的事情的影响(在许多其他严重的问题中)
编辑
有关安全密码存储的更多详细信息,请参阅matasano http://chargen.matasano.com/chargen/2015/3/26/enough-with-the-salts-updates-on-secure-password-schemes.html的安全忍者。
发布于 2015-02-10 18:04:17
在我看来,应该更强烈地注意到,使用salt的密码散列不再安全,不应该像其他人指出的那样使用PBKDF2或bcrypt。
https://stackoverflow.com/questions/28420682
复制相似问题