散列漏洞

时间:2018-12-18 13:06:39

标签: java hash cryptography

我想为我的项目添加一些安全性,所以我添加了密码字段。在其中,为了存储密码,我将使用txt并将其保存在其中,以提高安全性,我使用下面的代码对密码进行哈希处理(如果重要的话,可以使用这种方式保存多个密码)。这只是我进行哈希处理的示例,实际程序使用文本文件等。

public static void main(String[] args) throws NoSuchAlgorithmException {

    System.out.println("Enter Password: ");
    Scanner scanner = new Scanner(System.in);
    String enteredPassword = scanner.nextLine();
    String storedPassword = "�D�Ϛ-�UK�c�=�,�}��}��D��Zj>�m";

    MessageDigest messageDigest = MessageDigest.getInstance("SHA-256");
    messageDigest.update(enteredPassword.getBytes());
    String hashedString = new String(messageDigest.digest());
    System.out.println(hashedString);

    if(storedPassword.equals(hashedString)){
        System.out.println("Passwords Match!");   
    }else{
        System.out.println("Passwords Do Not Match!");
    }
}

我的问题是我是否可以安全地执行此操作,除了反编译我的项目并绕过此功能之外,我的项目还是安全的吗?或者可以利用此方法?另外,是否有一种方法可以保护项目免于反编译和重写代码以绕过安全功能?谢谢

2 个答案:

答案 0 :(得分:2)

方法本身是好的; SHA-256本身就是一个强大的单向哈希函数。它不能被“解密”。但这很快,因此可以使用字典对密码进行快速暴力破解。

为了提高安全性,您可以使用bcrypt或PBKDF2。大约100毫秒不会被用户注意到,但是使蛮力行不通。

下面是PBKDF2的示例,该示例使用100000次SHA-256迭代。它也使用随机盐。

SecureRandom random = SecureRandom.getInstanceStrong();
byte[] salt = new byte[16];
random.nextBytes(salt);
KeySpec spec = new PBEKeySpec("my-secret-password".toCharArray(), salt, 100000, 256);
SecretKeyFactory f = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
byte[] hash = f.generateSecret(spec).getEncoded();
Base64.Encoder enc = Base64.getEncoder();
System.out.printf("salt: %s%n", enc.encodeToString(salt));
System.out.printf("hash: %s%n", enc.encodeToString(hash));

注意:PBKDF2WithHmacSHA256从Java 8开始可用。


这是一个更完整的示例:

private static final SecureRandom random = new SecureRandom();

/**
 * One-way encrypts (hashes) the given password.
 * 
 * @param saltpw  the salt (will be generated when null)
 * @param pw      the password to encrypt
 * @return        encrypted salted password
 */
public static String encrypt(String saltpw, String pw) throws GeneralSecurityException {
    byte[] salt;
    if (saltpw == null) {
        salt = new byte[16];
        random.nextBytes(salt);
    } else {
        salt = Base64.getDecoder().decode(saltpw.replaceFirst("\\$.*", ""));
    }
    KeySpec spec = new PBEKeySpec(pw.toCharArray(), salt, 100000, 256);
    SecretKeyFactory f = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
    byte[] hash = f.generateSecret(spec).getEncoded();
    Base64.Encoder enc = Base64.getEncoder();
    return enc.encodeToString(salt) + "$" + enc.encodeToString(hash);
}

public static void main(String[] args) throws Exception {
    String enc = encrypt(null, "my-secret-password");
    System.out.printf("enc   : %s\n", enc);
    String test1 = encrypt(enc, "my-secret-password");
    System.out.printf("test 1: %s, valid: %b\n", test1, enc.equals(test1));
    String test2 = encrypt(enc, "some-other-password");
    System.out.printf("test 2: %s, valid: %b\n", test2, enc.equals(test2));
}

打印:

enc   : B5V6SjkjJpeOxvMAkPf7EA==$NNDA7o+Dpd+M+H99WVxY0B8adqVWJHZ+HIjgPxMljwo=
test 1: B5V6SjkjJpeOxvMAkPf7EA==$NNDA7o+Dpd+M+H99WVxY0B8adqVWJHZ+HIjgPxMljwo=, valid: true
test 2: B5V6SjkjJpeOxvMAkPf7EA==$4H1SpH8N+/jqU40G6RWb+ReHUB3C58iAaU4l39j+TV8=, valid: false

请注意,test 1产生的加密字符串与原始密码完全相同,而test 2(使用错误的密码)却没有。这样,您就可以通过仅比较散列来验证所提供的密码是否有效。

答案 1 :(得分:1)

没有办法禁止反编译Java。

但是,如果使用混淆器,可能会使您难以理解反编译的代码。 例如。 https://www.guardsquare.com/en/products/proguard

这会将所有方法名称,类名称,变量名称更改为无意义的短名称。 副作用是您的类文件也会缩小。