Jakie najlepsze praktyki należy zastosować w skrypcie logowania PHP?

27

Chcę ponownie napisać skrypty logowania do witryn klientów, aby były bardziej bezpieczne. Chcę wiedzieć, jakie najlepsze praktyki mogę wdrożyć w tym zakresie. Panele sterowania chronione hasłem są w obfitości, ale niewielu wydaje się sugerować najlepsze praktyki w zakresie pisania kodu, szybkości i bezpieczeństwa.

Będę używał PHP i bazy danych MYSQL.

Kiedyś używałem md5, ale widzę, że sha256 lub sha512 byłyby lepsze (wraz z bezpiecznym hashem i solą).

Niektóre skrypty logowania rejestrują adres IP podczas sesji lub nawet agenta użytkownika, ale chcę tego uniknąć, ponieważ nie jest on zgodny z serwerami proxy.

Jestem również trochę za najlepszymi praktykami w korzystaniu z sesji w PHP 5 (ostatnim razem, gdy czytałem PHP 4), więc niektóre najlepsze praktyki z tym byłyby pomocne.

Dzięki.

baryton
źródło
1
Podrzuć swój skrypt na codereview.SE!
Chris
@Chris CodeReview pomoc w zakresie przejrzystości kodu i tym podobnych. Na pewno nie powinieneś iść do nich ze względów bezpieczeństwa. Jeśli już, prawie zawsze będą przypominać ci, żebyś nie „rzucał własnym”, co jest w zasadzie tą samą odpowiedzią, jaką otrzyma w jakiejkolwiek społeczności programistów na SE.
Alternatex

Odpowiedzi:

21

Najlepiej jest nie wymyślać koła na nowo. Rozumiem jednak, że w świecie PHP znalezienie komponentu wysokiej jakości, który już to robi, może być trudne (nawet jestem prawie pewien, że frameworki implementują takie rzeczy, a ich implementacje są już przetestowane, solidne, poddane przeglądowi kodu itp. )

Jeśli z jakichś powodów nie możesz użyć frameworka, oto kilka sugestii:

Sugestie związane z bezpieczeństwem

  • Jeśli możesz, użyj PBKDF2 lub Bcrypt . To jest zrobione dla tego.

    Uzasadnienie: oba algorytmy mogą spowolnić proces haszowania, co jest dokładnie tym, czego chcesz, gdy hashujesz hasła (szybsze alternatywy oznaczają łatwiejszą brutalną siłę). Najlepiej jest dostosować parametry, aby proces stał się wolniejszy z czasem na tym samym sprzęcie, a nowy, szybszy sprzęt został wydany.

  • Jeśli nie możesz, przynajmniej nie używaj MD5 / SHA1. Nigdy. Zapomnij o tym . Na przykład użyj SHA512. Użyj też soli.

    Uzasadnienie: MD5 i SHA1 są zbyt szybkie. Jeśli atakujący ma dostęp do bazy danych zawierającej skróty i ma (nawet nie szczególnie) potężną maszynę, brutalne wymuszanie hasła jest szybkie i łatwe. Jeśli nie ma soli, zwiększa się szansa, że ​​atakujący znajdzie rzeczywiste hasło (co może spowodować dodatkowe szkody, jeśli hasło zostanie ponownie użyte w innym miejscu).

  • W PHP 5.5.0 i nowszych wersjach użyj password_hashi password_verify.

    Uzasadnienie: wywołanie funkcji zapewnianej przez framework jest łatwe, więc ryzyko popełnienia błędu jest zmniejszone. Dzięki tym dwóm funkcjom nie musisz myśleć o różnych parametrach, takich jak skrót. Pierwsza funkcja zwraca pojedynczy ciąg, który można następnie zapisać w bazie danych. Druga funkcja używa tego ciągu do weryfikacji hasła.

  • Chroń się przed brutalną siłą . Jeśli użytkownik poda nieprawidłowe hasło, gdy już podało inne nieprawidłowe hasło 0,01 sekundy temu, to dobry powód, aby je zablokować. Chociaż ludzie potrafią pisać szybko, prawdopodobnie nie mogą być tak szybcy.

    Inną ochroną byłoby ustawienie limitu awarii na godzinę. Jeśli użytkownik przesłał 3600 błędnych haseł w ciągu godziny, 1 hasło na sekundę, trudno uwierzyć, że jest to legalny użytkownik.

    Uzasadnienie: jeśli twoje hasła są zakodowane w niepewny sposób, brutalna siła może być bardzo skuteczna. Jeśli hasła są przechowywane bezpiecznie, brutalna siła wciąż marnuje zasoby serwera i przepustowość sieci, powodując niższą wydajność dla legalnych użytkowników. Wykrywanie brutalnej siły nie jest łatwe do opracowania i poprawnego działania, ale dla każdego innego niż niewielki system jest tego całkowicie warte.

  • Nie proś użytkowników o zmianę hasła co cztery tygodnie. Jest to bardzo denerwujące i zmniejsza bezpieczeństwo, ponieważ zachęca do bezpieczeństwa po zakończeniu.

    Uzasadnienie: pomysł, że wymuszanie zmiany haseł co n tygodni chroni system przed brutalną siłą, jest błędny. Ataki typu „brute force” zwykle kończą się powodzeniem w ciągu kilku sekund, minut, godzin lub dni, co sprawia, że ​​comiesięczne zmiany hasła są nieistotne. Z drugiej strony użytkownicy źle pamiętają hasła. Co więcej, jeśli będą musieli je zmienić, albo spróbują użyć bardzo prostych haseł, albo po prostu zanotują swoje hasła na post-it.

  • Kontroluj wszystko za każdym razem. Przechowuj dane logowania, ale nigdy nie przechowuj haseł w dzienniku kontroli. Upewnij się, że dziennik kontroli nie może zostać zmodyfikowany (tzn. Możesz dodać dane na końcu, ale nie modyfikować istniejących danych). Upewnij się, że dzienniki kontroli podlegają regularnej kopii zapasowej. Idealnie byłoby, gdyby logi były przechowywane na dedykowanym serwerze z bardzo ograniczonymi dostępami: jeśli zhakowany zostanie inny serwer, atakujący nie będzie w stanie wyczyścić logów, aby ukryć swoją obecność (i ścieżkę podjętą podczas ataku).

  • Nie zapamiętaj danych użytkownika w plikach cookie, chyba że użytkownik poprosi o to (pole „Pamiętaj mnie” musi być domyślnie odznaczone, aby uniknąć błędu ludzkiego).

Sugestie dotyczące łatwości użytkowania

  • Pozwól użytkownikowi zapamiętać hasło, jeśli chce, nawet jeśli większość przeglądarek ma już tę funkcję.
  • Nie używaj podejścia Google, gdy zamiast pytać o nazwę użytkownika i hasło, użytkownik jest czasami proszony tylko o hasło , a nazwa użytkownika jest już wyświetlana w <span/>. Przeglądarki nie mogą w tym przypadku wypełnić pola hasła (przynajmniej Firefox nie może tego zrobić), więc wymusza wylogowanie, a następnie zalogowanie się za pomocą zwykłego formularza wypełnionego przez przeglądarkę.
  • Nie używaj wyskakujących okienek z obsługą JavaScript do logowania. Łamie funkcje zapamiętywania haseł w przeglądarkach (i jest do kitu we wszystkich przypadkach).
  • Pozwól użytkownikowi wprowadzić swoją nazwę użytkownika lub adres e-mail . Kiedy się rejestruję, czasami nazwa użytkownika, którą chcę wprowadzić, jest już zajęta, więc muszę wymyślić nową. Mam wszelkie szanse, aby zapomnieć to imię za dwie godziny.
  • Zawsze przechowuj link do funkcji „Nie pamiętam hasła” w pobliżu formularza logowania. Nie wyświetlaj go tylko wtedy, gdy użytkownik nie zaloguje się: użytkownik, który w ogóle nie pamięta swojego hasła, nie ma pojęcia, że ​​musi podać nieprawidłowe hasło, aby zobaczyć link „Nie pamiętam hasła”.
  • Nie używaj zabezpieczeń po to .
  • Nie wymyślaj głupich reguł związanych z hasłem, aby je osłabić . Przykład: „Twoje hasło musi zaczynać się od małej litery.”; „Twoje hasło nie może zawierać spacji”.
Arseni Mourzenko
źródło
Nie napotkałem bcrypt. Jakie jest twoje uzasadnienie, aby to polecić? Dlaczego nie md5 / sha1? Dziękuję za resztę sugestii!
baryton
Rozumowanie jest proste: bcryptsą wykonywane przez osoby o wysokich kwalifikacjach. Jest także testowany, recenzowany itp. Nie ma więc powodu, aby sam wdrażać to samo. To jak tworzenie własnego algorytmu kryptograficznego dla swojej witryny. * „Dlaczego nie md5 / sha1?”: Patrz na przykład en.wikipedia.org/wiki/MD5#Security
Arseni Mourzenko
5
bcrypt działa wolno i, jak wspomniano, jest wdrażany przez profesjonalistów. md5 to algorytm mieszający, a nie szyfrowanie, które nie są dokładnie tym samym. Szybkie haszowanie pliku jest dobre, md5 byłby tutaj użyty ... haszowanie hasła nie musi być tak szybkie, bcrypt może tu pomóc. Powód, dla którego mówię, że brutalna siła staje się trudniejsza, gdy algorytm szyfrowania jest „wolny”.
Chris
2
@baritoneuk: minimum jest fajne. Ale nie mogę policzyć, ile stron odwiedziłem, które miały takie ograniczenia, jak maksymalna długość, brak znaków innych niż alfanumeryczne itp. Oszołomienie, jeśli i tak będziesz mieszać hasło - co mnie martwi, że nie są , po prostu przechowują go w swojej bazie danych w sposób wyraźny.
Carson63000
1
@Brian Ortiz: nie zawsze. Czasami dobrym pomysłem jest ustalenie limitu. Jeśli tego nie zrobisz, czy testujesz, czy aplikacja działa na dowolną długość? W jaki sposób? Jeśli tego nie przetestujesz, skąd możesz mieć pewność, że działa? Zamiast tego, ustawiając limit na rozsądną wartość, np. 100, możesz łatwo przetestować hasło o długości 100 znaków.
Arseni Mourzenko,
6
  1. Twoja strona powinna korzystać z HTTPS. W żadnym momencie nie należy prezentować strony logowania ani akceptować logowania z niezaszyfrowanego połączenia.
  2. Twoje pliki cookie powinny być ograniczone tylko do HTTP i ograniczone do bezpiecznych połączeń, jeśli używasz HTTPS.
  3. Proces logowania nie powinien zająć mniej niż 2 sekundy (1, jeśli uważasz, że 2 sekundy są za długie). Używaj bezpiecznego skrótu podczas przechowywania i weryfikacji haseł, i użyj soli, która jest trudniejsza do odgadnięcia. Użyj, bcryptjeśli to możliwe. W przeciwnym razie użyj innego rodzaju iterowanego skrótu.
  4. Nigdy nie twórz zapytań do bazy danych w żaden sposób, który wymaga użycia takich funkcji jak mysql_real_escape_string. Nigdy nie używaj konkatenacji ciągów, aby utworzyć zapytanie. Używaj przygotowanych, sparametryzowanych zapytań. Obsługuje go większość, jeśli nie wszystkie, sterowniki DB dla PHP. Jeśli nie wiesz jak to zrobić, spędzić trochę czasu na naukę, jak prepare, bindi executeza pomocą cokolwiek DB używasz. To jedyny pewny sposób, aby uchronić się przed wstrzyknięciem SQL. PDO obsługuje to.
  5. Zachęć użytkowników, aby nie używali tego samego hasła, którego używają do wiadomości e-mail. Przypomnij im, że jeśli Twoja witryna zostanie naruszona i jeśli użyją tego samego hasła w obu miejscach, ktoś może przejąć ich pocztę e-mail.
greyfade
źródło
+1 dla HTTPS, ponieważ ruch sieci publicznych jest coraz większy. Ale nie zgadzam się z tym, że punkt 3: 2 sekundy jest zbyt długi z punktu widzenia użytkowników. 0,5 s jest w porządku, szczególnie jeśli stosowane są inne techniki przeciwdziałania brutalnemu użyciu siły.
Arseni Mourzenko
Jestem zdezorientowany co do punktu nr 4. Jak można uniknąć konwencji ucieczki danych za pomocą mysql_real_escape_string? Wszystkim danym przesłanym przez użytkownika nie należy ufać i odpowiednio filtrować.
Chris
@chrisw: Tak, wszystkie dane wejściowe użytkownika powinny być traktowane tak, jakby były złośliwe. Ale gdy używasz sparametryzowanych zapytań, jest to najlepszy sposób na powstrzymanie wstrzykiwania SQL . Jeśli nie korzystasz z przygotowanych i parametryzowanych zapytań, jesteś podatny na iniekcję SQL. mysql_real_escape_stringto fałszywe bezpieczeństwo - to nie jest gwarancja. Zapytania sparametryzowane to.
greyfade
Zgadzam się teraz, po zapoznaniu się z nim. Funkcja: mysql_real_escape_string jest w większości bezpieczna, nie uważałbym tego za OGROMNĄ odpowiedzialność, ale widzę, jak korzystanie z przygotowanych instrukcji jest znacznie bardziej wydajne.
Chris
1
Możesz użyć PDO.
Felix G
1

Użyj solonego jednokierunkowego skrótu (najlepiej SHA512 przy użyciu http://au2.php.net/manual/en/function.hash.php ) ... w ten sposób, jeśli ktoś włamie się do twojej bazy danych, nawet jeśli zna sól , nie mogą wyodrębnić haseł (bez tabeli tęczy, która byłaby dłuższa dla SHA512).

Użyj HTTPS.

Nie wysyłaj potwierdzeń nazwy użytkownika / hasła pocztą elektroniczną z powrotem do użytkownika podczas rejestracji.

Jeśli zezwalasz na pliki cookie „zapamiętaj mnie” - dodaj dodatkowy login, aby uzyskać dostęp do funkcji administracyjnych i edycji profilu.

Jeśli użytkownik pomyli hasło, nie mów, że źle je podał (powiedz, że przez cały czas dostawali błędną nazwę użytkownika lub hasło) - w ten sposób mniej wskazówek na temat prawidłowych nazw użytkowników.

Spróbuj wdrożyć nazwę ekranową a login - w ten sposób mniej użytkowników będzie wyświetlać swoją nazwę logowania na listach użytkowników.

HorusKol
źródło
Całkowicie zgadzam się z tym, że nie wysyłam wiadomości e-mail w postaci zwykłego tekstu. Nie pamiętam, ile razy strony internetowe to robią. Jeśli masz 1 hasło do wszystkich stron (czego na szczęście nie mam), potencjalnie wszystkie strony są zagrożone. Takie strony prawdopodobnie przechowują również hasła w postaci zwykłego tekstu. westchnienie
baryton 1
1
  • Nigdy nie używaj algorytmów mieszających MD5 lub SHA1. Zawsze trzymaj się nowszych, takich jak SHA512
  • Zawsze używaj silnej, losowo generowanej soli
  • Nigdy nie wysyłaj swoim użytkownikom haseł, nawet w przypadku „Nie pamiętam hasła”
  • Nigdy nie używaj funkcji mysql_ *. Są od dawna amortyzowane. Trzymaj się ChNP
  • Nigdy nie przechowuj haseł w sesjach ani plikach cookie
Robin Thomas
źródło
0

Oto jedna rada: upewnij się, że nie można uzyskać dostępu do plików cookie za pomocą JS, aby zapobiec kradzieży, zobacz Ochrona plików cookie: artykuł Jeffa Atwoja

... Dzięki sprytnej konstrukcji zniekształcony adres URL po prostu potrafi przekraść się przez środek dezynfekujący. Ostatecznie wyrenderowany kod, oglądany w przeglądarce, ładuje i wykonuje skrypt z tego zdalnego serwera.

... ktokolwiek ładuje tę stronę profilu użytkownika, do której wstrzyknięto skrypt, właśnie nieświadomie przesłał pliki cookie swojej przeglądarki na zły serwer zdalny!

Jak już ustaliliśmy, gdy ktoś ma pliki cookie przeglądarki dla danej witryny, w zasadzie ma klucze do królestwa dla Twojej tożsamości ...

James
źródło