Jakiego typu kolumny / długości powinienem użyć do przechowywania zaszyfrowanego hasła Bcrypt w bazie danych?

317

Chcę przechowywać hashowane hasło (za pomocą BCrypt) w bazie danych. Jaki byłby do tego dobry typ i która miałaby odpowiednią długość? Czy hasła mieszane z BCrypt są zawsze tej samej długości?

EDYTOWAĆ

Przykładowy skrót:

$2a$10$KssILxWNR6k62B7yiX0GAe2Q7wwHlrzhF3LqtVvpyvHZf0MwvNfVu

Po haszowaniu niektórych haseł wydaje się, że BCrypt zawsze generuje 60 znaków haszowania.

EDYCJA 2

Przepraszamy za brak wzmianki o implementacji. Używam jBCrypt .

helpermethod
źródło
Zobacz także strukturę hashowania haseł PHP Openwall (PHPass). Jest przenośny i odporny na wiele typowych ataków na hasła użytkowników. Facet, który napisał framework (SolarDesigner), to ten sam facet, który napisał John The Ripper i zasiada jako sędzia w konkursie Hashing Competition . Więc wie coś więcej o atakach na hasła.
jww
1
Jeśli ktoś wpadnie na to, szukając rozwiązania dla scrypt : odpowiedź Gumbo dotyczy również scrypt. Osobiście zastosowałem BINARY (64) w MySQL, co pozwoliło mi później sprawdzić równość bajtów w Pythonie.
Philippe Hebert

Odpowiedzi:

368

Modułowy format krypt dla bcrypt składa się z

  • $2$, $2a$Lub $2y$identyfikacji algorytmu i format mieszającego
  • dwucyfrowa wartość oznaczająca parametr kosztu, po której następuje $
  • A 53 znaków bazowym 64 kodowane wartości (używają alfabetu ., /, 0- 9, A- Z, a- z, która różni się od standardowej podstawy 64 Kodowanie alfabetu) składający się z:
    • 22 znaki soli (w rzeczywistości tylko 128 bitów ze 132 zdekodowanych bitów)
    • 31 znaków zaszyfrowanego wyjścia (w rzeczywistości tylko 184 bity ze 186 zdekodowanych bitów)

Zatem całkowita długość wynosi odpowiednio 59 lub 60 bajtów.

Podczas korzystania z formatu 2a potrzebujesz 60 bajtów. A tym samym dla MySQL Ja polecam używać CHAR(60) BINARYlubBINARY(60) (patrz The _bin i binarnych sortowania w celu uzyskania informacji na temat różnicy).

CHARnie jest binarnie bezpieczny, a równość nie zależy wyłącznie od wartości bajtów, ale od faktycznego zestawienia; w najgorszym przypadku Ajest traktowany jako równy a. Aby uzyskać więcej informacji, zobacz The _binand binaryCollations .

Gumbo
źródło
28
Pamiętaj - przechowywanie jako binarne (60) może spowodować nieoczekiwane zachowanie równości łańcuchów (między innymi). W .NET można temu zaradzić, używając String.Equals (fromDataBaseBinary60string, typicalishString, StringComparison.InvariantCulture)
JHubbard80
8
Jeśli zdefiniujesz kolumnę jako ZNAK (60) ZNAK ZESTAWU latin1 COLLATE latin1_bin, zyskasz teraz zalety dokładnego porównywania ciągów bez potrzeby stosowania kolumny binarnej.
Ben
2
@AndreFigueiredo SQL_Latin1_General_CP1_CS_ASjest nieznany w MySQL. To, co jest znane, to latin1_general_cs.
Gumbo
1
Chciałbym mieć definicję tutaj co 2, 2ai 2yśrednią dla algorytmu i formatu mieszający. Nie mogłem znaleźć prostej odpowiedzi przy wyszukiwaniu.
żartem
2
@Neon Problem polega na tym, że możesz porównać różne wartości skrótu, aby były równe. Jeśli wyraźnie określisz, że jest to kolumna binarna (lub VARCHAR z odpowiednim zestawieniem), nie ryzykujesz, że gdzie indziej zmienisz jakieś ustawienie, które czyni porównanie bez rozróżniania wielkości liter. Usprawnia również twoją intencję, co jest ogólnie rzeczą dobrą - przechowujesz dane binarne; powinieneś przechowywać go jako dane binarne.
Pozew Fund Moniki w
51

Hash Bcrypt może być przechowywany w BINARY(40)kolumnie.

BINARY(60), jak sugerują inne odpowiedzi, jest najłatwiejszym i najbardziej naturalnym wyborem, ale jeśli chcesz zmaksymalizować wydajność pamięci, możesz zaoszczędzić 20 bajtów, bezstratnie dekodując skrót. Udokumentowałem to dokładniej na GitHub: https://github.com/ademarre/binary-mcf

Skróty Bcrypt mają strukturę określaną jako modułowy format krypt (MCF). Binarny MCF (BMCF) dekoduje te tekstowe reprezentacje skrótów do bardziej zwartej struktury binarnej. W przypadku Bcrypt wynikowy hasz binarny ma 40 bajtów.

Gumbo wykonał niezłą robotę, wyjaśniając cztery składniki skrótu Bcrypt MCF:

$<id>$<cost>$<salt><digest>

Dekodowanie do BMCF wygląda następująco:

  1. $<id>$ może być reprezentowany w 3 bitach.
  2. <cost>$, 04-31, można przedstawić w 5 bitach. Połącz je razem dla 1 bajtu.
  3. 22-znakowa sól jest (niestandardową) zasadą 64 reprezentującą 128 bitów. Dekodowanie Base-64 daje 16 bajtów.
  4. 31-znakowy skrót skrótu może być zdekodowany w formacie base-64 do 23 bajtów.
  5. Zbierz wszystko razem dla 40 bajtów: 1 + 16 + 23

Możesz przeczytać więcej na powyższy link lub sprawdzić moją implementację PHP , także na GitHub.

I czerwony
źródło
49
Koszt dłuższego pola: 20 bajtów razy nawet milion + rekordów: 20 MB, gdy osiągniesz milion rekordów +. Koszt niewłaściwej implementacji skróconej długości pola w wysoce złożonym obszarze bezpieczeństwa i inżynierii: $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ $$$$$$$$$$$$$$$$$$$$$$$$$$$$
Kzqai,
6
@Kzqai, jak powiedziałem, większa 60-bajtowa kolumna jest najbardziej naturalnym wyborem, ale to, jak agresywnie dąży się do wydajności przechowywania, zależy od projektu. Na przykład często próbuje się zmieścić całą bazę danych w pamięci, a tutaj 20 MB i kolejne 20 można szybko dodać w środowisku o ograniczonej pamięci.
Andre D
10
Twój przykład wpisuje się w mój punkt widzenia. --- Jeśli chcesz umieścić swoją bazę danych w pamięci, zoptymalizuj każdą inną kolumnę przed dotknięciem kolumny pamięci bcrypt. --- Jeśli zoptymalizowałeś każdą inną kolumnę do szalonych stopni i pozostała tylko kolumna haszująca bcrypt, zdobądź kolejny gigabajt pamięci tylko na bcrypt. --- Jeśli zrobiłeś oba powyższe ... ... przestań, nie zoptymalizowałeś co drugiej kolumny nisko wiszących owoców i masz zamiar zadzierać ze sprawdzonym kryptograficznym systemem bezpieczeństwa, który działa, i zastąp z bardziej skomplikowanym rodzimym systemem z szansą niepowodzenia wdrożenia.
Kzqai,
11
@Kzqai Nie ma ryzyka osłabienia bezpieczeństwa twojej biblioteki Bcrypt. Jest to kodowanie danych, które jest cofane podczas pobierania z pamięci przed sprawdzeniem hasła. To nie jest terytorium „nie rzucaj własnym krypto”.
Andre D,
1
Ładne wyjaśnienie. :) Chociaż twoje wyjaśnienie dało świetny pomysł, po prostu chcę iść z 60 znakami, nawet 100 znakami, po prostu dla bezpieczeństwa. Również niezła debata @Kzqai i AndreD
Naveen Kumar V
23

Jeśli używasz PHP password_hash()z PASSWORD_DEFAULTalgorytmem do generowania skrótu bcrypt (który, jak zakładam, stanowi duży procent osób czytających to pytanie), pamiętaj, że w przyszłości password_hash()może używać innego algorytmu jako domyślnego, a zatem może to wpływa na długość skrótu (ale niekoniecznie musi być dłuższy).

Ze strony podręcznika:

Zauważ, że ta stała ma się zmieniać wraz z upływem czasu wraz z dodawaniem nowych i silniejszych algorytmów do PHP. Z tego powodu długość wyniku używania tego identyfikatora może zmieniać się w czasie. Dlatego zaleca się przechowywanie wyniku w kolumnie bazy danych, która może być dłuższa niż 60 znaków (255 znaków byłoby dobrym wyborem).

Używając bcrypt, nawet jeśli masz 1 miliard użytkowników (tzn. Obecnie konkurujesz z Facebookiem) do przechowywania 255 bajtów skrótów haseł, to tylko ~ 255 GB danych - mniej więcej wielkości małego dysku twardego SSD. Jest bardzo mało prawdopodobne, aby przechowywanie skrótu hasła było wąskim gardłem w Twojej aplikacji. Jednak nie jest prawdopodobne, że przestrzeń dyskowa jest z jakiegoś powodu problemem, możesz użyć PASSWORD_BCRYPTsiły, password_hash()aby użyć bcrypt, nawet jeśli nie jest to domyślne. Pamiętaj tylko, aby być informowanym o wszelkich lukach wykrytych w bcrypt i przeglądać informacje o wydaniu za każdym razem, gdy nowa wersja PHP jest wydawana. Jeśli domyślny algorytm zostanie kiedykolwiek zmieniony, dobrze byłoby sprawdzić powód i podjąć świadomą decyzję, czy użyć nowego algorytmu, czy nie.

Mikrofon
źródło
20

Nie wydaje mi się, aby istniały jakieś fajne sztuczki, które można zrobić, przechowując to, jak na przykład za pomocą skrótu MD5.

Myślę, że najlepszym rozwiązaniem jest przechowywanie go w postaci CHAR(60)60 znaków

James C.
źródło
Chociaż dokumentacja PHP stwierdza, że ​​kolumny powinny być w stanie pomieścić więcej danych, w przyszłych wydaniach ...
Julian F. Weinert
16
Bez powodu do złotej płyty. Jeśli używane oprogramowanie wymaga sześćdziesięciu bajtów, przydziel sześćdziesiąt bajtów. Jeśli w oprogramowaniu pojawi się przyszła wersja, która to zmieni, możesz się tym martwić, kiedy to nastąpi. Nie powinieneś automatycznie instalować aktualizacji zmieniających funkcjonalność.
Tyler Crompton