2012-09-19 8 views
8

Używam Shiro w aplikacji do uwierzytelnienia. Używam hashed hasło z solą i przechowywać je w mojej bazy danych tak:Jak zapełniać i używać soli Shiro z bazy danych

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); 
} 

przechowywać sól z ciąg w mojej bazy danych. Teraz w moim królestwie chcę odzyskać moje dane z bazy danych, używam do tego usługi transakcyjnej. Ale moja sól jest silny, więc chcę go zawrócić jako typ ByteSource metodą statyczną:

ByteSource byteSourceSalt = Util.bytes(salt); //where the salt is a String 

ale kiedy tworzę SaltedAuthenticationInfo nie dopuszczonego.

myślę, mój problem jest z mojej metody konwersji:

private String byteArrayToHexString(byte[] bArray){ 

     StringBuffer buffer = new StringBuffer(); 

     for(byte b : bArray) { 
      buffer.append(Integer.toHexString(b)); 
      buffer.append(" "); 
     } 

return buffer.toString().toUpperCase();  
} 

Dzięki za pomoc.

Odpowiedz

13

Jak wspomniano w doskonałej odpowiedzi https://stackoverflow.com/a/20206115/603901, Shiro DefaultPasswordService już generuje unikalne sole dla każdego hasła.

Nie ma jednak potrzeby implementowania niestandardowej usługi PasswordService w celu dodania soli prywatnej (czasami nazywanej "pieprzem") do soli dla użytkownika. Prywatna sól może być skonfigurowany w 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 

kod Java do generowania mieszania dopasowywanie hasło:

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"); 

Powstały hash wygląda tak:

$shiro1$SHA-256$500000$An4HRyqMJlZ58utACtyGDQ==$nKbIY9Nd9vC89G4SjdnDfka49mZiesjWgDsO/4Ly4Qs= 

Sól prywatne nie jest przechowywany w bazie danych, co utrudnia złamanie haseł, gdy przeciwnik uzyska dostęp do zrzutu bazy danych.

Przykład ten został stworzony przy użyciu shiro-1.2.2

Dzięki https://github.com/Multifarious/shiro-jdbi-realm/blob/master/src/test/resources/shiro.ini o pomoc ze składnią dla shiro.ini

+1

w jaki sposób mogę uzyskać automatyczne generowanie soli przez shiro w celu przechowywania go w oddzielnej kolumnie w db – thoitbk

4

Czy obejrzałeś PasswordMatcher/PasswordService?

To już ma wbudowaną wbudowaną logikę kodowania/dekodowania/porównywania. Aby go użyć:

Przechowywanie haseł w bazie:

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); 
} 

Następnie można po prostu użyć PasswordMatcher jako dopasowującego w swoim królestwie.

realm.setCredentialsMatcher(new PasswordMatcher()); 

lub w shiro.ini:

matcher = org.apache.shiro.authc.credential.PasswordMatcher 
realm.credentialsMatcher = $matcher 
+4

Ok, dzięki za odpowiedź. Spróbuję tego. Ale nie rozumiem, gdzie muszę teraz używać mojej soli i gdzie jest link między hasłem a solą. – Fred37b

1

mogę zmienić typ dla oszczędzania mojego soli. Teraz używam bajtu [] zamiast ciągu.

ByteSource salt = randomNumberGenerator.nextBytes(32); 

byte[] byteTabSalt = salt.getBytes(); 

A ja przechowuję bajtTabSalt w mojej bazie danych.

4

Implementacja DefaultPasswordService automatycznie dodaje losową sól do każdego połączenia encryptPassword. Ta "publiczna" sól będzie przechowywana w "hashedPasswordBase64", który otrzymasz z "encryptPassword".

Ponieważ "publiczna" sól jest generowana indywidualnie dla każdego hashowanego hasła, nie można "po prostu" wygenerować tabeli tęczy i brutalnie wymusić wszystkie zaszyfrowane hasła naraz. Dla każdego zakodowanego hasła osoba atakująca musiałaby wygenerować własny, unikalny stół tęczy ze względu na unikalną sól "publiczną". Do tej pory nie musisz dodawać dodatkowej soli do bazy danych.

Aby jeszcze bardziej zabezpieczyć przechowywane hasła hashowane, można dodać "prywatną" sól, która powinna być przechowywana w innym miejscu - o ile nie jest w bazie danych. Korzystając z "prywatnej" soli, możesz chronić hashowane hasła przed brutalnym atakiem na tęczowy stół, ponieważ atakujący nie zna "prywatnej" soli i nie może uzyskać "prywatnej" soli z wpisów w bazie danych.

Jest to bardzo prosty przykład jak stworzyć PasswordService który wykorzystuje „prywatny” sól przewidziany jako stały ciąg i że działa jako CredentialsMatcher:

public class MyPrivateSaltingPasswortService extends DefaultPasswordService 
{ 
    public MyPrivateSaltingPasswortService() 
    { 
     super(); 
     HashService service = getHashService(); 
     if (service instanceof DefaultHashService) 
     { 
     ((DefaultHashService) service).setPrivateSalt(
      new SimpleByteSource("MySuperSecretPrivateSalt")); 
     } 
    } 
} 

następnie może wykorzystać swoją realizację w Shiro.ini:

[main] 
saltedService = com.mycompany.MyPrivateSaltingPasswortService 
matcher = org.apache.shiro.authc.credential.PasswordMatcher 
matcher.passwordService = $saltedService 
realm.credentialsMatcher = $matcher 

Przykład ten został stworzony przy użyciu shiro-1.2.2

+0

Czy mógłbyś wyjaśnić: "Implementacja DefaultPasswordService automatycznie dodaje losową sól do każdego połączenia encryptPassword." Sól "publiczna będzie przechowywana w" hashedPasswordBase64 ", który otrzymasz z" encryptPassword "."? Nie rozumiem, czy ta sól publiczna musi być zapisana w osobnej kolumnie (nie kolumnie z hasłem)? –

+0

Do tej pory nie trzeba dodawać dodatkowej soli do bazy danych. - Co miałeś na myśli tutaj? –

+1

Witaj Pasza, wygenerowany token zawiera kilka różnych bloków informacji. jednym z tych bloków jest sól publiczna, więc Shiro może ponownie włączyć i ponownie przetestować hasło wprowadzone przez użytkownika. tak długo jak przechowujesz wygenerowany token "tak jak jest", nie musisz przechowywać publicznej soli - nie musisz nawet o tym wiedzieć, ponieważ Shiro zajmuje się tym. Proszę spojrzeć na odpowiedź Mikaela Falkvidda - istnieje przykład wygenerowanego tokena, a także opcja definiowania prywatnej soli. – seafoxx

Powiązane problemy