W celu wygenerowania 32-znakowego tokena dostępu do naszego API używamy obecnie:
$token = md5(uniqid(mt_rand(), true));
Czytałem, że ta metoda nie jest kryptograficznie bezpieczna, ponieważ opiera się na zegarze systemowym, a to openssl_random_pseudo_bytes
byłoby lepsze rozwiązanie, ponieważ byłoby trudniejsze do przewidzenia.
W takim przypadku jak wyglądałby równoważny kod?
Zakładam coś takiego, ale nie wiem, czy to prawda ...
$token = md5(openssl_random_pseudo_bytes(32));
Jaka długość ma sens, którą powinienem przekazać funkcji?
md5()
generuje 32-znakowy ciąg, ale zawiera tylko 128-bitowe dane.openssl_random_pseudo_bytes()
zwraca prawdziwe dane binarne, więc ma 32 * 8 = 256 bitów losowości. Wypychając 32-bajtowy losowy ciąg przez md5, skutecznie zmniejszasz jego wyjątkowość o ogromną ilość.$token = bin2hex(openssl_random_pseudo_bytes(16));
wystarczająca, czy potrzebuję pętli 16 iteracji przekazujących 1 jako długość i dołączanych szesnastkowo do ciągu?Random::alphanumericString($length)
, które mieści około 2 miliardy razy więcej „entropii” w tych 16 znakach.Odpowiedzi:
Oto poprawne rozwiązanie:
$token = bin2hex(openssl_random_pseudo_bytes(16)); # or in php7 $token = bin2hex(random_bytes(16));
źródło
bin2hex(random_bytes($length/2))
ponieważ możesz mieć 2 znaki szesnastkowe na każdy bajt, więc liczba znaków będzie zawsze podwojona$length
bez tego$length
liczby znaków (zamiast dbać o rozmiar bajtu), będziesz chciał ją przekazaćrandom_bytes($length/2)
.Jeśli chcesz użyć openssl_random_pseudo_bytes, najlepiej użyć implementacji CrytoLib, pozwoli ci to wygenerować wszystkie znaki alfanumeryczne, przyklejanie bin2hex wokół openssl_random_pseudo_bytes spowoduje po prostu uzyskanie AF (kapsli) i liczb.
Zastąp ścieżkę / do / miejscem, w którym umieściłeś plik cryptolib.php (możesz go znaleźć na GitHub pod adresem : https://github.com/IcyApril/CryptoLib )
<?php require_once('path/to/cryptolib.php'); $token = IcyApril\CryptoLib::randomString(16); ?>
Pełna dokumentacja CryptoLib jest dostępna pod adresem : https://cryptolib.ju.je/ . Obejmuje wiele innych losowych metod, szyfrowanie kaskadowe oraz generowanie i walidację skrótów; ale jest tam, jeśli tego potrzebujesz.
źródło
openssl_random_pseudo_bytes(16)
każdy bajt może mieć dowolną wartość (0-255), podczas gdyrandomString(16)
każdy bajt może mieć tylko az Az 0-9, czyli 62 kombinacje na bajt. Tak, randomString jest lepsze dla każdej długości łańcucha , ponieważ bin2hex jest nieefektywne kodowanie (50%); lepiej użyćbase64_encode(openssl_random_pseudo_bytes(16))
dla krótszego ciągu i dokładnej znanej liczby bajtów bezpieczeństwa (w tym przypadku 16, ale zmień w razie potrzeby)+
,/
i=
znaków, więc jeśli próbujesz wygenerować przyjazny dla użytkownika tokena (np klucz API) nie jest idealny.Jeśli masz bezpieczny kryptograficznie generator liczb losowych, nie musisz haszować jego danych wyjściowych. W rzeczywistości nie chcesz. Po prostu użyj
$token = openssl_random_pseudo_bytes($BYTES,true)
Gdzie $ BYTES to dowolna liczba bajtów danych. MD5 ma 128-bitowy hash, więc wystarczy 16 bajtów.
Na marginesie, żadna z funkcji, które wywołujesz w oryginalnym kodzie, nie jest bezpieczna kryptograficznie, większość jest na tyle szkodliwa, że użycie tylko jednej z nich byłoby niebezpieczne, nawet w połączeniu z innymi bezpiecznymi funkcjami. MD5 ma problemy z bezpieczeństwem (chociaż w przypadku tej aplikacji mogą one nie mieć zastosowania). Uniqid nie tylko domyślnie nie generuje kryptograficznie losowych bajtów (ponieważ używa zegara systemowego), ale dodana entropia, którą przekazujesz, jest łączona za pomocą liniowego generatora przystającego, który nie jest bezpieczny kryptograficznie. W rzeczywistości prawdopodobnie oznacza to, że można by odgadnąć wszystkie klucze API, mając dostęp do kilku z nich, nawet jeśli nie mieliby pojęcia o wartości zegara serwera. Wreszcie, mt_rand (), której używasz jako dodatkowej entropii, również nie jest bezpiecznym generatorem liczb losowych.
źródło
Wiarygodne hasła Możesz tworzyć tylko znaki ascii a-zA-Z i cyfry 0-9 . Aby to zrobić, najlepiej jest używać tylko metod bezpiecznych kryptograficznie, takich jak random_int () lub random_bytes () z PHP7. Pozostałe funkcje jak base64_encode () Możesz używać tylko jako funkcji pomocniczych, aby zwiększyć wiarygodność łańcucha i zmienić go na znaki ASCII .
mt_rand () nie jest bezpieczna i jest bardzo stara. Z dowolnego ciągu Musisz użyć random_int (). Z łańcucha binarnego Powinieneś użyć base64_encode (), aby łańcuch binarny był niezawodny lub bin2hex, ale wtedy ograniczysz bajt tylko do 16 pozycji (wartości). Zobacz moją implementację tej funkcji. Używa wszystkich języków.
źródło