Java / SpringBoot: проверка соленого хэша возвращает неправильный хэш - PullRequest
0 голосов
/ 03 июня 2019

Итак, я сейчас изучаю SpringBoot и сейчас пытаюсь сохранить пароль вместе с другими данными для пользователей в базе данных (MySql).Для того, чтобы это было безопасно, я использую соленые хэши для хранения.Генерация этих хешей и сохранение их в базе данных работает нормально, однако, когда я пытаюсь подтвердить пароль, взяв соль и пароль, я получаю другой хеш, поэтому неверный результат.

Ниже приведен мой код.

Во-первых: класс User, где я начинаю проверку

@Entity
public class User {

@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
private long uID;

@NotNull
private String nname;

@NotNull
private String vname;
private String email;
private String telnr;
@Embedded
private Address address;

@NotNull
private boolean isAdmin;

private String hash;

// Default Constructor
public User() {
}

// Constructor
public User(String name, String vname, String email, String telnr, Address address, boolean isAdmin,
        String password) throws NoSuchAlgorithmException {
    HashHelper hashHelper = new HashHelper();

    this.nname = name;
    this.vname = vname;
    this.email = email;
    this.telnr = telnr;
    this.address = address;
    this.isAdmin = isAdmin;
    this.hash = hashHelper.createHash(password);
}

public boolean validateHash(String password) {
    HashHelper hashHelper = new HashHelper();
    // Get the used Salt
    String[] parts = this.hash.split(":");
    byte[] salt = parts[0].getBytes();

    // Create Hash with old salt
    String newHash = hashHelper.getHash(password, salt);
    if (parts[1] == newHash) {
        return true;
    }

    return false;
}

Во-вторых, мой класс HashHelper, где я обрабатываю все, что связано с хэшированием.Я использую createHash всякий раз, когда сохраняется новый пароль (следовательно, новая соль) и getHash для проверки с помощью конкретной соли.

public class HashHelper {

    public HashHelper() {
    }

    public byte[] getSalt() throws NoSuchAlgorithmException {

        SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
        byte[] salt = new byte[16];
        sr.nextBytes(salt);

        return salt;
    }

// Create Salt and Hash and store them, seperated by :
        public String createHash(String password) throws NoSuchAlgorithmException {
            String hash = null;
            byte[] salts = getSalt();

        try {
            MessageDigest md = MessageDigest.getInstance("SHA-256");

            md.update(salts);

            byte[] bytes = md.digest(password.getBytes());
            StringBuilder sb = new StringBuilder();

            for (int i = 0; i < bytes.length; i++) {
                sb.append(Integer.toString((bytes[i] & 0xff) + 0x100, 16).substring(1));
            }

            hash=salts.toString() + ":" + sb.toString();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }

        System.out.println("Hash: " + hash);
        return hash;
    }

    public String getHash(String password, byte[] salt) {
        String hash = "";
        try {
            MessageDigest md = MessageDigest.getInstance("SHA-256");

            md.update(salt);

            byte[] bytes = md.digest(password.getBytes());
            StringBuilder sb = new StringBuilder();

            for (int i = 0; i < bytes.length; i++) {
                sb.append(Integer.toString((bytes[i] & 0xff) + 0x100, 16).substring(1));
            }

            hash = sb.toString();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        return hash;
    }

}

Вызов для проверки устанавливается в CommandLineRunner только для тестирования ивыглядит следующим образом:

    Optional<User> user = userRepository.findById((long)10);
    if (user.get().validateHash("Password")) {
            System.out.println("Correct Password");
    }
    else {
            System.out.println("Wrong password");
    }

Я думаю, что это было связано с методами getBytes() и toString(), потому что byte[] salt имеет меньшую длину, когда я пытаюсь его проверить (около 11-12 байт вместо 16) но я не могу понять, почему.Любая помощь будет принята с благодарностью!

1 Ответ

2 голосов
/ 03 июня 2019

Ваш вопрос спорный, потому что вы не должны использовать этот алгоритм для хэширования паролей, так как он небезопасен.Даже если вы не защищаете ничего важного, пользователи могут использовать один и тот же пароль в нескольких местах, и когда злоумышленник взломает вашу таблицу небезопасных паролей, он сможет использовать многие из этих паролей в другом месте.

Использование Argon2или, по крайней мере, PBKDF2 для хэширования паролей, по крайней мере, с 10 000 раундов хэширования.

Причина, по которой у вас возникают проблемы, заключается в том, что вы не храните соль, которую используете для хэширования пароля.Без этого вы никогда не сможете вычислить один и тот же хеш.Проблема в salts.toString() в методе createHash():

hash=salts.toString() + ":" + sb.toString();

Вызов toString() для byte[] ничего не говорит вам о содержимом массива.Вот почему вы приложили все усилия, чтобы преобразовать результат дайджеста bytes в шестнадцатеричное.Вы должны сделать что-то похожее на соль.

Аналогично, вызов getBytes() для строки просто кодирует строку с кодировкой по умолчанию для вашей платформы.Это не то, что вам нужно.

Убедитесь, что вы используете их метод equals() при сравнении String экземпляров.Оператор == только скажет вам, являются ли они идентичным экземпляром.

При хранении байтовых массивов, что вам все равно нужно будет сделать с хорошим алгоритмом хеширования, я рекомендую использовать base-64, так как тамэто отличная поддержка в java.util.Base64, и она даст более компактные кодировки вашего массива.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...