W zeszłym tygodniu przeczytałem wiele artykułów na temat haszowania haseł, a Blowfish wydaje się być (jednym z) najlepszych obecnie algorytmów haszujących - ale to nie jest temat tego pytania!
Limit 72 znaków
Blowfish bierze pod uwagę tylko pierwsze 72 znaki wpisanego hasła:
<?php
$password = "Wow. This is a super secret and super, super long password. Let's add some special ch4r4ct3rs a#d everything is fine :)";
$hash = password_hash($password, PASSWORD_BCRYPT);
var_dump($password);
$input = substr($password, 0, 72);
var_dump($input);
var_dump(password_verify($input, $hash));
?>
Wynik to:
string(119) "Wow. This is a super secret and super, super long password. Let's add some special ch4r4ct3rs a#d everything is fine :)"
string(72) "Wow. This is a super secret and super, super long password. Let's add so"
bool(true)
Jak widać, liczą się tylko pierwsze 72 znaki. Twitter używa Blowfish czyli bcrypt do przechowywania swoich haseł ( https://shouldichangemypassword.com/twitter-hacked.php ) i zgadnij, co: zmień swoje hasło do twittera na długie hasło z więcej niż 72 znakami i możesz zalogować się na swoje konto przez wpisując tylko pierwsze 72 znaki.
Rozdymka i pieprz
Istnieje wiele różnych opinii na temat „pieprzenia” haseł. Niektórzy twierdzą, że jest to niepotrzebne, ponieważ trzeba założyć, że tajny łańcuch pieprzu jest również znany / opublikowany, więc nie poprawia haszyszu. Mam oddzielny serwer bazy danych, więc jest całkiem możliwe, że wyciekła tylko baza danych, a nie stały pieprz.
W tym przypadku (pieprz nie wyciekł) utrudniasz atak w oparciu o słownik (popraw mnie, jeśli to nie jest w porządku). Jeśli wycieknie również papryka: nie jest tak źle - nadal masz sól i jest tak dobrze chroniona, jak haszysz bez pieprzu.
Więc myślę, że pieprzenie hasła nie jest przynajmniej złym wyborem.
Sugestia
Moja sugestia, aby uzyskać skrót Blowfish dla hasła składającego się z więcej niż 72 znaków (i pieprzu) to:
<?php
$pepper = "foIwUVmkKGrGucNJMOkxkvcQ79iPNzP5OKlbIdGPCMTjJcDYnR";
// Generate Hash
$password = "Wow. This is a super secret and super, super long password. Let's add some special ch4r4ct3rs a#d everything is fine :)";
$password_peppered = hash_hmac('sha256', $password, $pepper);
$hash = password_hash($password_peppered, PASSWORD_BCRYPT);
// Check
$input = substr($password, 0, 72);
$input_peppered = hash_hmac('sha256', $input, $pepper);
var_dump(password_verify($input_peppered, $hash));
?>
Opiera się to na tym pytaniu : password_verify
powrót false
.
Pytanie
Jaki jest bezpieczniejszy sposób? Uzyskujesz najpierw skrót SHA-256 (który zwraca 64 znaki), czy rozważasz tylko pierwsze 72 znaki hasła?
Plusy
- Użytkownik nie może się zalogować, wprowadzając tylko pierwsze 72 znaki
- Możesz dodać pieprz bez przekraczania limitu znaków
- Wynik funkcji hash_hmac miałby prawdopodobnie większą entropię niż samo hasło
- Hasło jest szyfrowane przez dwie różne funkcje
Cons
- Tylko 64 znaki są używane do zbudowania haszyszu blowfish
Edycja 1: To pytanie dotyczy tylko integracji Blowfish / bcrypt z PHP. Dziękuję za komentarze!
Odpowiedzi:
Tutaj problem jest zasadniczo problemem entropii. Zacznijmy więc tam szukać:
Entropia na znak
Liczba bitów entropii na bajt to:
Zatem to, jak działamy, zależy od tego, jakich postaci oczekujemy.
Pierwszy problem
Pierwszym problemem z twoim kodem jest to, że twój krok mieszający "pepper" generuje znaki szesnastkowe (ponieważ czwarty parametr
hash_hmac()
to nie jest ustawiony).Dlatego haszując pieprz, skutecznie zmniejszasz maksymalną entropię dostępną dla hasła o współczynnik 2 (od 576 do 288 możliwych bitów).
Drugi problem
Jednak w pierwszej kolejności
sha256
dostarcza tylko256
bitów entropii. Więc skutecznie zmniejszasz możliwe 576 bitów do 256 bitów. Twój haszujący krok * natychmiast *, z samej definicji traci co najmniej 50% możliwej entropii hasła.Możesz częściowo rozwiązać ten problem, przełączając się na
SHA512
, gdzie zmniejszyłbyś dostępną entropię tylko o około 12%. Ale to wciąż niemała różnica. Te 12% zmniejsza liczbę permutacji o współczynnik1.8e19
. To duża liczba ... I to jest czynnik, który ją zmniejsza o ...Problem podstawowy
Podstawową kwestią jest to, że istnieją trzy rodzaje haseł przekraczających 72 znaki. Wpływ, jaki ten system stylu będzie miał na nich, będzie bardzo różny:
Uwaga: od tego momentu zakładam, że porównujemy do systemu pieprzowego, który używa
SHA512
surowego wyjścia (nie szesnastkowego).Losowe hasła o wysokiej entropii
To są twoi użytkownicy używający generatorów haseł, które generują duże klucze do haseł. Są losowe (generowane, a nie wybrane przez człowieka) i mają wysoką entropię na znak. Te typy używają dużych bajtów (znaki> 127) i niektórych znaków sterujących.
W przypadku tej grupy funkcja haszująca znacznie zmniejszy ich dostępną entropię do
bcrypt
.Powtórzę to. W przypadku użytkowników, którzy używają długich haseł o dużej entropii, Twoje rozwiązanie znacznie zmniejsza siłę hasła o wymierną wartość. (62 bity entropii utracone dla 72-znakowego hasła i więcej dla dłuższych haseł)
Losowe hasła o średniej entropii
Ta grupa używa haseł zawierających popularne symbole, ale bez dużych bajtów ani znaków sterujących. To są Twoje hasła, które możesz wpisać.
Dla tej grupy zamierzasz nieco odblokować większą entropię (nie twórz jej, ale pozwól, aby większa entropia pasowała do hasła bcrypt). Kiedy mówię trochę, mam na myśli trochę. Próg rentowności występuje, gdy maksymalnie przekroczysz 512 bitów, które ma SHA512. Dlatego szczyt wynosi 78 znaków.
Powtórzę to jeszcze raz. W przypadku tej klasy haseł można przechowywać tylko 6 dodatkowych znaków, zanim zabraknie entropii.
Nielosowe hasła o niskiej entropii
To jest grupa, która używa znaków alfanumerycznych, które prawdopodobnie nie są generowane losowo. Coś w rodzaju cytatu z Biblii lub czegoś takiego. Te frazy mają około 2,3 bitów entropii na znak.
W przypadku tej grupy możesz znacznie odblokować większą entropię (nie tworzyć jej, ale pozwolić, aby więcej pasowało do wpisanego hasła bcrypt) przez haszowanie. Próg rentowności wynosi około 223 znaków, zanim zabraknie entropii.
Powtórzmy to jeszcze raz. W przypadku tej klasy haseł wstępne haszowanie zdecydowanie zwiększa bezpieczeństwo.
Powrót do prawdziwego świata
Tego rodzaju obliczenia entropii nie mają tak naprawdę większego znaczenia w prawdziwym świecie. Liczy się zgadywanie entropii. To bezpośrednio wpływa na to, co mogą zrobić atakujący. To właśnie chcesz zmaksymalizować.
Chociaż niewiele jest badań poświęconych odgadywaniu entropii, jest kilka punktów, na które chciałbym zwrócić uwagę.
Szanse na przypadkowe odgadnięcie 72 poprawnych znaków z rzędu są niezwykle niskie. Bardziej prawdopodobne jest, że wygrasz w loterii Powerball 21 razy, niż zderzenie ... Tak duża liczba, o której mówimy.
Ale statystycznie nie możemy się na to natknąć. W przypadku fraz szansa na to, że pierwsze 72 znaki będą takie same, jest dużo większa niż w przypadku hasła losowego. Ale wciąż jest trywialnie niski (bardziej prawdopodobne jest, że wygrasz w loterii Powerball 5 razy, w oparciu o 2,3 bita na postać).
Praktycznie
Praktycznie to nie ma znaczenia. Szanse na prawidłowe odgadnięcie pierwszych 72 znaków, w przypadku których te ostatnie robią znaczącą różnicę, są tak niskie, że nie warto się tym martwić. Czemu?
Cóż, powiedzmy, że bierzesz zdanie. Jeśli dana osoba może poprawnie uzyskać pierwsze 72 znaki, to albo naprawdę ma szczęście (mało prawdopodobne), albo jest to powszechne zdanie. Jeśli jest to powszechna fraza, jedyną zmienną jest czas jej wykonania.
Weźmy przykład. Weźmy cytat z Biblii (tylko dlatego, że jest to częste źródło długiego tekstu, a nie z żadnego innego powodu):
To 180 znaków. 73. znak jest
g
w drugimneighbor's
. Jeśli tak dużo zgadłeś, prawdopodobnie nie zatrzymasz się na tymnei
, ale przejdziesz do reszty wersetu (ponieważ w ten sposób prawdopodobnie zostanie użyte hasło). Dlatego twój „hash” niewiele dodał.BTW: ABSOLUTNIE NIE jestem zwolennikiem używania cytatu z Biblii. W rzeczywistości jest dokładnie odwrotnie.
Wniosek
Tak naprawdę nie pomożesz ludziom, którzy używają długich haseł, najpierw je zhaszuj. Niektórym grupom zdecydowanie możesz pomóc. Niektórych zdecydowanie możesz zranić
Ale ostatecznie nic z tego nie jest zbyt istotne. Liczby, z którymi mamy do czynienia, są po prostu DUŻO za wysokie. Różnica w entropii nie będzie duża.
Lepiej zostaw bcrypt takim, jakim jest. Bardziej prawdopodobne jest, że schrzanisz hasz (dosłownie, już to zrobiłeś i nie jesteś pierwszy ani ostatni, który popełnia ten błąd), niż atak, któremu próbujesz zapobiec.
Skoncentruj się na zabezpieczeniu pozostałej części witryny. I dodaj miernik entropii hasła do pola hasła podczas rejestracji, aby wskazać siłę hasła (i wskazać, czy hasło jest zbyt długie, aby użytkownik mógł chcieć je zmienić) ...
To co najmniej moje 0,02 dolara (lub prawdopodobnie znacznie więcej niż 0,02 dolara) ...
O ile używa się „sekretnej” papryki:
Nie ma dosłownie żadnych badań nad wprowadzeniem jednej funkcji skrótu do bcrypt. Dlatego w najlepszym przypadku nie jest jasne, czy wprowadzenie „zasypanego” hasha do bcrypt kiedykolwiek spowoduje nieznane luki w zabezpieczeniach (wiemy, że
hash1(hash2($value))
może to ujawnić znaczące luki w zakresie odporności na kolizje i ataków typu preimage).Biorąc pod uwagę, że już rozważasz przechowywanie tajnego klucza („pieprzu”), dlaczego nie użyć go w dobrze przestudiowany i zrozumiały sposób? Dlaczego nie zaszyfrować hasha przed jego przechowywaniem?
Zasadniczo, po zaszyfrowaniu hasła, wprowadź całe dane wyjściowe skrótu do silnego algorytmu szyfrowania. Następnie zapisz zaszyfrowany wynik.
Teraz atak SQL-Injection nie spowoduje wycieku niczego użytecznego, ponieważ nie mają klucza szyfrującego. A jeśli klucz wycieknie, atakującym nie będzie lepiej, niż gdybyś użył zwykłego skrótu (co można udowodnić, coś z pieprzowym „pre-hashem” nie zapewnia).
Uwaga: jeśli zdecydujesz się to zrobić, skorzystaj z biblioteki. W przypadku PHP zdecydowanie polecam Zend Framework 2
Zend\Crypt
pakiet . Właściwie to jedyny, który polecam w obecnym momencie. Został mocno sprawdzony i podejmuje wszystkie decyzje za Ciebie (co jest bardzo dobrą rzeczą) ...Coś jak:
use Zend\Crypt\BlockCipher; public function createHash($password) { $hash = password_hash($password, PASSWORD_BCRYPT, ["cost"=>$this->cost]); $blockCipher = BlockCipher::factory('mcrypt', array('algo' => 'aes')); $blockCipher->setKey($this->key); return $blockCipher->encrypt($hash); } public function verifyHash($password, $hash) { $blockCipher = BlockCipher::factory('mcrypt', array('algo' => 'aes')); $blockCipher->setKey($this->key); $hash = $blockCipher->decrypt($hash); return password_verify($password, $hash); }
Jest to korzystne, ponieważ używasz wszystkich algorytmów w sposób, który jest dobrze zrozumiany i dobrze zbadany (przynajmniej względnie). Zapamiętaj:
źródło
Podawanie haseł jest z pewnością dobrą rzeczą, ale zobaczmy, dlaczego.
Najpierw powinniśmy odpowiedzieć na pytanie, kiedy dokładnie pieprz pomaga. Pieprz chroni tylko hasła, o ile pozostaje w tajemnicy, więc jeśli atakujący ma dostęp do samego serwera, nie jest to przydatne. Dużo łatwiejszym atakiem jest jednak SQL-injection, który umożliwia odczyt bazy danych (do naszych wartości hash), przygotowałem demo SQL-injection, aby pokazać, jakie to proste (kliknij w następną strzałkę, aby przygotować Wejście).
W takim razie w czym tak naprawdę pomaga pieprz? Dopóki pieprz pozostaje tajemnicą, chroni słabe hasła przed atakiem słownikowym. Hasło
1234
stałoby się wtedy czymś w rodzaju1234-p*deDIUZeRweretWy+.O
. To hasło jest nie tylko znacznie dłuższe, ale zawiera również znaki specjalne i nigdy nie będzie częścią żadnego słownika.Teraz możemy oszacować, jakich haseł będą używać nasi użytkownicy, prawdopodobnie więcej użytkowników będzie wprowadzać słabe hasła, ponieważ są użytkownicy z hasłami o długości od 64 do 72 znaków (w rzeczywistości będzie to bardzo rzadkie).
Kolejną kwestią jest zakres brutalnej siły. Funkcja skrótu sha256 zwróci wyjście 256 bitów lub kombinację 1.2E77, to o wiele za dużo dla brutalnego wymuszania, nawet dla GPU (jeśli obliczyłem poprawnie, wymagałoby to około 2E61 lat na GPU w 2013). Nie mamy więc prawdziwej wady stosując pieprz. Ponieważ wartości skrótu nie są systematyczne, nie można przyspieszyć brutalnego wymuszania za pomocą typowych wzorców.
PS O ile wiem, limit 72 znaków jest specyficzny dla samego algorytmu BCrypt. Najlepsza odpowiedź, jaką znalazłem, jest taka .
PPS Myślę, że twój przykład jest wadliwy, nie możesz wygenerować skrótu z pełną długością hasła i zweryfikować go skróconym. Prawdopodobnie zamierzałeś zastosować pieprz w ten sam sposób do generowania skrótu i do weryfikacji skrótu.
źródło
true
. O to właśnie chodzi w tym pytaniu. ZobaczcieBcrypt wykorzystuje algorytm oparty na drogim algorytmie konfiguracji klucza Blowfish.
Zalecany 56-bajtowy limit hasła (w tym zerowy bajt zakończenia) dla bcrypt odnosi się do 448-bitowego limitu klucza Blowfish. Żadne bajty wykraczające poza ten limit nie są w pełni mieszane z wynikowym hashem. Bezwzględny limit 72 bajtów haseł bcrypt jest zatem mniej istotny, jeśli weźmie się pod uwagę rzeczywisty wpływ tych bajtów na wynikowy hash.
Jeśli myślisz, że Twoi użytkownicy zwykle wybierają hasła o długości ponad 55 bajtów, pamiętaj, że zawsze możesz zamiast tego zwiększyć liczbę rund rozciągania haseł, aby zwiększyć bezpieczeństwo w przypadku naruszenia tabeli haseł (chociaż musi to być dużo w porównaniu z dodaniem dodatkowych postacie). Jeśli prawa dostępu użytkowników są tak krytyczne, że użytkownicy normalnie wymagaliby bardzo długiego hasła, wówczas wygaśnięcie hasła również powinno być krótkie, np. 2 tygodnie. Oznacza to, że prawdopodobieństwo, że hasło pozostanie ważne, jest znacznie mniejsze, podczas gdy haker inwestuje swoje zasoby w pokonanie czynnika pracy związanego z testowaniem każdego hasła próbnego, aby sprawdzić, czy wygeneruje pasujący skrót.
Oczywiście w przypadku braku naruszenia tablicy haseł powinniśmy pozwolić hakerom na co najwyżej dziesięć prób odgadnięcia 55-bajtowego hasła użytkownika, przed zablokowaniem konta użytkownika;)
Jeśli zdecydujesz się wstępnie zaszyfrować hasło, które jest dłuższe niż 55 bajtów, powinieneś użyć SHA-384, ponieważ ma największy wynik bez przekraczania limitu.
źródło