Obecnie jestem studentem i studiuję PHP, próbuję wykonać proste szyfrowanie / deszyfrowanie danych w PHP. Zrobiłem kilka poszukiwań online i niektóre z nich były dość mylące (przynajmniej dla mnie).
Oto, co próbuję zrobić:
Mam tabelę składającą się z tych pól (ID użytkownika, Fname, Lname, Email, Password)
Chcę mieć wszystkie pola zaszyfrowane, a następnie odszyfrowane (czy można użyć sha256
do szyfrowania / deszyfrowania, jeśli nie algorytmu szyfrowania)
Kolejną rzeczą, której chcę się nauczyć, jest to, jak tworzyć jednokierunkowe hash(sha256)
połączenie z dobrą „solą”. (Zasadniczo chcę mieć prostą implementację szyfrowania / deszyfrowania, proszę hash(sha256)+salt)
pana, pańskie odpowiedzi byłyby bardzo pomocne i bardzo docenione. Dziękuję ++
php
security
encryption
cryptography
encryption-symmetric
Randel Ramirez
źródło
źródło
Odpowiedzi:
Przedmowa
Zaczynając od definicji tabeli:
Oto zmiany:
Fname
,Lname
iEmail
zostaną zaszyfrowane przy użyciu symetrycznego szyfru, dostarczone przez OpenSSL ,IV
Pole będzie przechowywać wektor inicjujący używany do szyfrowania. Wymagania dotyczące przechowywania zależą od używanego szyfrowania i trybu; więcej o tym później.Password
Pole zostanie zakodowane przy użyciu jednokierunkowej hash hasła,Szyfrowanie
Szyfr i tryb
Wybór najlepszego szyfru i trybu szyfrowania wykracza poza zakres tej odpowiedzi, ale ostateczny wybór wpływa na rozmiar zarówno klucza szyfrowania, jak i wektora inicjalizacji; w tym poście będziemy używać AES-256-CBC, który ma stały rozmiar bloku 16 bajtów i rozmiar klucza 16, 24 lub 32 bajty.
Klucz szyfrowania
Dobry klucz szyfrowania to binarny obiekt blob wygenerowany z niezawodnego generatora liczb losowych. Zalecany byłby następujący przykład (> = 5,3):
Można to zrobić raz lub wiele razy (jeśli chcesz utworzyć łańcuch kluczy szyfrujących). Zachowaj je jak najbardziej poufne.
IV
Wektor inicjalizacyjny dodaje losowość do szyfrowania i jest wymagany w trybie CBC. Idealnie byłoby, gdyby te wartości były używane tylko raz (technicznie raz na klucz szyfrowania), więc aktualizacja dowolnej części wiersza powinna ją ponownie wygenerować.
Dostępna jest funkcja pomagająca w generowaniu IV:
Przykład
Zaszyfrujmy pole nazwy, używając wcześniejszego
$encryption_key
i$iv
; aby to zrobić, musimy dopełnić nasze dane do rozmiaru bloku:Wymagania dotyczące przechowywania
Zaszyfrowane dane wyjściowe, podobnie jak IV, są binarne; przechowywanie tych wartości w bazie danych można osiągnąć za pomocą wyznaczonych typów kolumn, takich jak
BINARY
lubVARBINARY
.Wartość wyjściowa, podobnie jak IV, jest binarna; aby przechowywać te wartości w MySQL, rozważ użycie
BINARY
lubVARBINARY
kolumn. Jeśli nie ma takiej opcji, możesz również przekonwertować dane binarne na reprezentację tekstową za pomocąbase64_encode()
lubbin2hex()
, wymaga to od 33% do 100% więcej miejsca na dysku.Deszyfrowanie
Odszyfrowanie przechowywanych wartości jest podobne:
Uwierzytelnione szyfrowanie
Możesz dodatkowo poprawić integralność wygenerowanego tekstu zaszyfrowanego, dołączając podpis, który jest generowany z tajnego klucza (innego niż klucz szyfrowania) i zaszyfrowanego tekstu. Przed odszyfrowaniem tekstu zaszyfrowanego podpis jest najpierw weryfikowany (najlepiej metodą porównywania w czasie stałym).
Przykład
Zobacz też:
hash_equals()
Haszowanie
W miarę możliwości należy unikać przechowywania odwracalnego hasła w bazie danych; chcesz tylko zweryfikować hasło, a nie znać jego zawartość. Jeśli użytkownik zgubi swoje hasło, lepiej pozwolić mu je zresetować, zamiast wysyłać mu swoje oryginalne (upewnij się, że resetowanie hasła można wykonać tylko przez ograniczony czas).
Stosowanie funkcji skrótu jest operacją jednokierunkową; następnie można go bezpiecznie używać do weryfikacji bez ujawniania oryginalnych danych; w przypadku haseł metoda brutalnej siły jest wykonalnym podejściem do ich ujawnienia ze względu na jej stosunkowo krótką długość i zły dobór haseł przez wiele osób.
Algorytmy haszujące, takie jak MD5 lub SHA1, zostały stworzone w celu sprawdzenia zawartości plików względem znanej wartości skrótu. Są one znacznie zoptymalizowane, aby weryfikacja była jak najszybsza, a jednocześnie była dokładna. Biorąc pod uwagę ich stosunkowo ograniczoną przestrzeń wyjściową, łatwo było zbudować bazę danych ze znanymi hasłami i odpowiadającymi im wyjściami mieszania, tęczowymi tablicami.
Dodanie soli do hasła przed haszowaniem sprawiłoby, że tęczowa tablica byłaby bezużyteczna, ale ostatnie postępy w sprzęcie sprawiły, że wyszukiwanie brutalne stało się opłacalnym podejściem. Dlatego potrzebujesz algorytmu haszującego, który jest celowo wolny i po prostu niemożliwy do optymalizacji. Powinien również być w stanie zwiększyć obciążenie szybszego sprzętu bez wpływu na możliwość weryfikacji istniejących skrótów haseł, aby zapewnić przyszłą ochronę.
Obecnie dostępne są dwie popularne opcje:
W tej odpowiedzi wykorzystany zostanie przykład z bcrypt.
Pokolenie
Skrót hasła można wygenerować w następujący sposób:
Sól jest generowana w
openssl_random_pseudo_bytes()
celu utworzenia losowej porcji danych, która jest następnie przepuszczanabase64_encode()
istrtr()
dopasowywana do wymaganego alfabetu[A-Za-z0-9/.]
.W
crypt()
pełni funkcję wycieniowanie podstawie algorytmu ($2y$
na Blowfish), czynnik kosztowy (współczynnik 13 zajmuje z grubsza 0.40s na maszynie do 3 GHz) i sól 22 znaków.Uprawomocnienie
Po pobraniu wiersza zawierającego informacje o użytkowniku weryfikujesz hasło w następujący sposób:
Aby zweryfikować hasło, dzwonisz
crypt()
ponownie, ale przekazujesz poprzednio obliczony skrót jako wartość soli. Wartość zwracana daje ten sam skrót, jeśli podane hasło jest zgodne z hashem. Aby zweryfikować hash, często zaleca się użycie funkcji porównania w stałym czasie, aby uniknąć ataków czasowych.Haszowanie haseł w PHP 5.5
PHP 5.5 wprowadziło funkcje haszowania haseł , których możesz użyć do uproszczenia powyższej metody haszowania:
I weryfikacja:
Zobacz również:
password_hash()
,password_verify()
źródło
$iv_size = 16;
:$iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length("AES-256-CBC"))
w celu wskazania związku między rozmiarem iv do użycia z użytym szyfrem. Możesz również rozszerzyć nieco potrzebę (lub nie)pkcs7_pad()
/pkcs7_unpad()
lub po prostu uprościć post, pozbywając się ich i używając "aes-256-ctr". Świetny post @ Ja͢ckMyślę, że odpowiedziano na to już wcześniej ... ale tak czy inaczej, jeśli chcesz zaszyfrować / odszyfrować dane, nie możesz użyć SHA256
źródło
Tło odpowiedzi i wyjaśnienie
Aby zrozumieć to pytanie, musisz najpierw zrozumieć, czym jest SHA256. SHA256 to kryptograficzna funkcja skrótu . Cryptographic Hash Function to funkcja jednokierunkowa, której dane wyjściowe są kryptograficznie bezpieczne. Oznacza to, że obliczenie skrótu (odpowiednik szyfrowania danych) jest łatwe, ale trudno jest uzyskać oryginalne dane wejściowe za pomocą skrótu (odpowiednik odszyfrowania danych). Ponieważ użycie kryptograficznej funkcji skrótu oznacza, że odszyfrowanie jest niewykonalne obliczeniowo, dlatego nie można wykonać deszyfrowania za pomocą SHA256.
To, czego chcesz użyć, to funkcja dwukierunkowa, a dokładniej szyfr blokowy . Funkcja, która umożliwia zarówno szyfrowanie, jak i deszyfrowanie danych. Funkcje
mcrypt_encrypt
imcrypt_decrypt
domyślnie używają algorytmu Blowfish. Sposób użycia mcrypt przez PHP można znaleźć w tym podręczniku . Istnieje również lista definicji szyfrów służących do wyboru szyfru używanego przez mcrypt. Wiki dotyczące Blowfish można znaleźć w Wikipedii . Szyfr blokowy szyfruje dane wejściowe w blokach o znanym rozmiarze i położeniu za pomocą znanego klucza, dzięki czemu dane można później odszyfrować za pomocą klucza. Tego właśnie SHA256 nie może Ci zapewnić.Kod
źródło
Oto przykład wykorzystujący openssl_encrypt
źródło
mcrypt_create_iv()
, użyłbym:openssl_random_pseudo_bytes(openssl_cipher_iv_length($encryptionMethod))
, w ten sposób metodologia działa dla dowolnej wartości $ encryptionMethod i będzie używać tylko openssl rozszerzenie.false
doopenssl_decrypt()
. Zobacz stackoverflow.com/q/41952509/1066234 Ponieważ szyfry blokowe, takie jak AES, wymagają, aby dane wejściowe były dokładną wielokrotnością rozmiaru bloku (16 bajtów dla AES), konieczne jest wypełnienie.źródło
Zajęło mi trochę czasu, aby dowiedzieć się, jak nie uzyskać
false
podczas używaniaopenssl_decrypt()
i uzyskać szyfrowanie i odszyfrowywanie.Jeśli chcesz przekazać zaszyfrowany ciąg za pośrednictwem adresu URL, musisz zakodować ciąg jako urlen:
Aby lepiej zrozumieć, co się dzieje, przeczytaj:
Aby wygenerować 16-bajtowe klucze, możesz użyć:
Aby zobaczyć komunikaty o błędach openssl, możesz użyć:
echo openssl_error_string();
Mam nadzieję, że to pomoże.
źródło