Spring безопасность 3.1.4 и стирание ShaPasswordEncoder

Сегодня я обновил версию безопасности spring приложения, над которым я работаю, начиная с 3.1.3 до 3.1.4, и я заметил предупреждение об отказе в классе org.springframework.security.authentication.encoding.ShaPasswordEncoder.

Итак, я переключился на новую реализацию org.springframework.security.crypto.password.StandardPasswordEncoder.

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

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

Смотрите также: Как использовать новый PasswordEncoder из spring Безопасность

Ответ 1

Если вы хотите переключиться на более безопасный механизм кодирования паролей, я бы рекомендовал вам использовать BCrypt. Я бы использовал что-то вроде этого, чтобы перенести ваших пользователей:

// Implement the old PasswordEncoder interface
public class MigrateUsersPasswordEncoder implements PasswordEncoder {
    @Autowired
    ShaPasswordEncoder legacyEncoder;
    @Autowired
    JdbcTemplate template;

    BCryptPasswordEncoder bcryptEncoder = new BCryptPasswordEncoder();

    @Override
    public String encodePassword(String rawPass, Object salt) {
        return bcryptEncoder.encode(rawPass);
    }

    @Override
    public boolean isPasswordValid(String encPass, String rawPass, Object salt) {
        if (legacyEncoder.isPasswordValid(encPass, rawPass, salt)) {
            template.update("update users set password = ? where password = ?", bcryptEncoder.encode(rawPass), encPass);
            return true;
        }
        return bcryptEncoder.matches(rawPass, encPass);
    }
}

Вы можете проверить, какая доля пользователей была перенесена в формате поля пароля. Строки BCrypt имеют отличительный синтаксис, начинающийся с знака $.

Один из других ответов указывает, что этот код может случайно обновить несколько паролей одновременно. В вопросе говорилось, что используется обычная соль, поэтому вероятность столкновения незначительна, если соль выбрана случайным образом, но это может быть не всегда так. Если бы были обновлены два пароля, какова будет проблема? Тогда было бы возможно обнаружить, что учетные записи имеют одинаковый пароль из хэширования bcrypt. Это так или иначе, так как это требует, чтобы хэши SHA были одинаковыми для обновления. Если вы считаете, что это может быть проблемой (например, из-за плохого выбора соли или даже использования несоленых хэшей), было бы тривиально модифицировать SQL, чтобы обнаружить это, и выполнить несколько обновлений с отдельными значениями хэш-значения BCrypt.

Ответ 2

Я попытался добавить комментарий к принятому ответу, но, увы, у меня пока нет достаточного количества кредитов.: (

Я считаю, что принятый фрагмент кода ответа потенциально опасен там, где он обновляет пароль в базе данных. Если ShaPasswordEncoder производит такие же результаты при шифровании (именно поэтому делается предположение, что старый пароль можно найти, и я убедился, что это определенно верно, по крайней мере, с нулевой солью на ShaPasswordEncoder), вы по-прежнему не можете гарантировать, что пароль уникален среди всех пользователей. Вы случайно можете использовать тот же пароль, что и другой пользователь в системе, и этот код SQL в конечном итоге изменит всех пользователей, у которых есть ваш пароль.

Я думаю, что самая безопасная стратегия - не обновлять пароль пользователя и вместо этого предоставлять стратегию миграции, которая планирует окончательное удаление ShaPasswordEncoder.

  • Используйте предоставленный пример кода.
  • Удалите код, который обновляет базу данных.
  • Добавьте функцию, например "Забыли пароль" или "Создать новый пароль", чтобы обработать возможный случай, когда пользователи не создали новый пароль при удалении ShaPasswordEncoder. Как и при обновлении до Spring безопасности, которая удалена, или выберите ее самостоятельно.
  • Обновите свою документацию или дайте понять, что в следующей крупной версии программного обеспечения пользователям придется перезаписывать свои пароли или использовать предыдущую функцию reset.
  • Предоставьте пользователю льготный период перехода к основной версии версии (они, вероятно, этого не сделают и просто поймают в пароле reset).

Ответ 3

Это отличный вопрос, и я с нетерпением жду некоторых ответов.

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