Как хранить и использовать соль Широ из базы данных
Я использую Широ в приложении для аутентификации. Я использую хешированный пароль с солью и храню их в своей базе данных следующим образом:
private User createUserWithHashedPassword(String inName, String inFirstName, String inLastName, String inPassword){
ByteSource salt = randomNumberGenerator.nextBytes(32);
byte[] byteTabSalt = salt.getBytes();
String strSalt = byteArrayToHexString(byteTabSalt);
String hashedPasswordBase64 = new Sha256Hash(inPassword, salt, 1024).toBase64();
return new User(inName,inFirstName,inLastName,hashedPasswordBase64,strSalt);
}
Я храню соль со строкой в моей базе данных. Теперь в моем мире я хочу вернуть свои данные из базы данных, для этого я использую сервис транзакций. Но моя соль - Strong, поэтому я хочу, чтобы она снова превратилась в тип ByteSource со статическим методом:
ByteSource byteSourceSalt = Util.bytes(salt); //where the salt is a String
Но когда я создаю свой SaltedAuthenticationInfo, он не авторизуется.
Я думаю, что моя проблема в моем методе конвертации:
private String byteArrayToHexString(byte[] bArray){
StringBuffer buffer = new StringBuffer();
for(byte b : bArray) {
buffer.append(Integer.toHexString(b));
buffer.append(" ");
}
return buffer.toString().toUpperCase();
}
Спасибо за вашу помощь.
4 ответа
Как упоминалось в превосходном ответе /questions/771493/kak-hranit-i-ispolzovat-sol-shiro-iz-bazyi-dannyih/771501#771501, служба DefaultPasswordService Shiro уже генерирует уникальные соли для каждого пароля.
Однако нет необходимости реализовывать собственный PasswordService для добавления частной соли (иногда называемой "перцем") к солям для каждого пользователя. Частная соль может быть настроена в shiro.ini:
[main]
hashService = org.apache.shiro.crypto.hash.DefaultHashService
hashService.hashIterations = 500000
hashService.hashAlgorithmName = SHA-256
hashService.generatePublicSalt = true
# privateSalt needs to be base64-encoded in shiro.ini but not in the Java code
hashService.privateSalt = myVERYSECRETBase64EncodedSalt
passwordMatcher = org.apache.shiro.authc.credential.PasswordMatcher
passwordService = org.apache.shiro.authc.credential.DefaultPasswordService
passwordService.hashService = $hashService
passwordMatcher.passwordService = $passwordService
Java-код для генерации подходящего хэша пароля:
DefaultHashService hashService = new DefaultHashService();
hashService.setHashIterations(HASH_ITERATIONS); // 500000
hashService.setHashAlgorithmName(Sha256Hash.ALGORITHM_NAME);
hashService.setPrivateSalt(new SimpleByteSource(PRIVATE_SALT)); // Same salt as in shiro.ini, but NOT base64-encoded.
hashService.setGeneratePublicSalt(true);
DefaultPasswordService passwordService = new DefaultPasswordService();
passwordService.setHashService(hashService);
String encryptedPassword = passwordService.encryptPassword("PasswordForThisUser");
Полученный хеш выглядит так:
$shiro1$SHA-256$500000$An4HRyqMJlZ58utACtyGDQ==$nKbIY9Nd9vC89G4SjdnDfka49mZiesjWgDsO/4Ly4Qs=
Частная соль не хранится в базе данных, что затрудняет взлом паролей, если злоумышленник получает доступ к дампу базы данных.
Этот пример был создан с использованием shiro-1.2.2
Спасибо https://github.com/Multifarious/shiro-jdbi-realm/blob/master/src/test/resources/shiro.ini за помощь с синтаксисом для shiro.ini
Вы смотрели на PasswordMatcher / PasswordService?
Это уже имеет всю встроенную логику кодирования / декодирования / сравнения. Чтобы использовать это:
Хранение пароля в базе данных:
PasswordService service = new DefaultPasswordService(); // or use injection or shiro.ini to populate this
private User createUserWithHashedPassword(String inName, String inFirstName, String inLastName, String inPassword){
String hashedPasswordBase64 = service.encryptPassword(inPassword);
return new User(inName,inFirstName,inLastName,hashedPasswordBase64,strSalt);
}
Тогда вы можете просто использовать PasswordMatcher в качестве сопоставителя в вашей сфере.
realm.setCredentialsMatcher(new PasswordMatcher());
или в shiro.ini:
matcher = org.apache.shiro.authc.credential.PasswordMatcher
realm.credentialsMatcher = $matcher
Реализация DefaultPasswordService автоматически добавляет случайную соль в каждый вызов encryptPassword. Эта "публичная" соль будет храниться в "hashedPasswordBase64", который вы получаете от "encryptPassword".
Поскольку "открытая" соль генерируется индивидуально для каждого хешированного пароля, нельзя "просто" создать радужную таблицу и перебрать все ваши хешированные пароли сразу. Для каждого хешированного пароля злоумышленник должен создать собственную уникальную радужную таблицу из-за уникальной "публичной" соли. Пока вам не нужно вносить дополнительную соль в базу данных.
Чтобы сделать сохраненные хешированные пароли еще более безопасными, вы также можете добавить "приватную" соль, которая должна храниться где-либо еще - до тех пор, пока ее нет в базе данных. Используя "приватную" соль, вы можете защитить хешированные пароли от атаки "грубой силы" по радужным таблицам, поскольку злоумышленник не знает "частную" соль и не может получить "приватную" соль из записей базы данных.
Это очень простой пример того, как создать PasswordService, который использует "приватную" соль, представленную как константную строку, и которая работает как CredentialsMatcher:
public class MyPrivateSaltingPasswortService extends DefaultPasswordService
{
public MyPrivateSaltingPasswortService()
{
super();
HashService service = getHashService();
if (service instanceof DefaultHashService)
{
((DefaultHashService) service).setPrivateSalt(
new SimpleByteSource("MySuperSecretPrivateSalt"));
}
}
}
Затем вы можете использовать свою собственную реализацию в shiro.ini:
[main]
saltedService = com.mycompany.MyPrivateSaltingPasswortService
matcher = org.apache.shiro.authc.credential.PasswordMatcher
matcher.passwordService = $saltedService
realm.credentialsMatcher = $matcher
Этот пример был создан с использованием shiro-1.2.2
Я меняю свой тип для сохранения моей соли. Теперь я использую byte[] вместо String.
ByteSource salt = randomNumberGenerator.nextBytes(32);
byte[] byteTabSalt = salt.getBytes();
И я храню byteTabSalt в своей базе данных.