Czy warto haszować hasła po stronie klienta

135

Kiedy chcę wprowadzić system logowania, zawsze porównuję MD5 podanego hasła z jego wartością w tabeli użytkowników po stronie serwera.

Jednak mój znajomy powiedział mi, że „czyste” hasło może zostać wykryte przez oprogramowanie sieciowe.

Moje pytanie brzmi: czy warto zaszyfrować hasło po stronie klienta? Czy to lepsze niż haszowanie po stronie serwera?

Zakaria
źródło
1
Myślałem o zaszyfrowaniu hasła po stronie klienta, ale tylko po to, aby mieć pewność, że hasło klienta nigdy nie istnieje jako czysty tekst po stronie serwera, co oznacza, że ​​mogą czuć się łatwiej, wiedząc, że nie znam ich rzeczywistego hasła, lub nie może łatwo z tego zrezygnować, jeśli zostanie naruszona czy jestem szalony?
Cyclone
1
Tylko dla kompletności, ponieważ mówimy o bezpieczeństwie, a MD5 zostało wspomniane w OP: Podczas szyfrowania hasła należy zawsze używać soli. Używanie zwykłego, niesolonego MD5 jest tylko nieznacznie lepsze niż przechowywanie haseł w postaci zwykłego tekstu w bazie danych.
sffc
1
@Cyclone Hashing TYLKO po stronie klienta jest zdecydowanie złym pomysłem, ponieważ jeśli atakujący w jakiś sposób zna hash, może go użyć do zalogowania się tak, jakby znał hasło, omijając kod mieszający po stronie klienta.
Teejay
6
@Teejay: Dlatego nie wysyłasz czystego skrótu. Serwer wysyła losową sól do klienta, dodajesz skrót hasła i ponownie haszujesz całość, a następnie odsyłasz z powrotem do serwera, który wykonuje te same obliczenia. Atak powtórkowy nie udaje się, ponieważ sól będzie inna
MSalters
3
Czy to pytanie nie powinno być zakończone na security.stackexchange.com?
efr4k

Odpowiedzi:

122

Zasadniczo twój przyjaciel ma rację. Ale po prostu mieszania hasła po stronie klienta jest tylko po prostu lepiej niż złożenie go jako zwykły tekst na serwer. Ktoś, kto może nasłuchiwać haseł w postaci zwykłego tekstu, z pewnością jest również w stanie nasłuchiwać zaszyfrowanych haseł i używać tych przechwyconych skrótów do uwierzytelniania na serwerze.

W tym przypadku bezpieczniejsze protokoły uwierzytelniania zwykle przeskakują przez wiele obręczy, aby upewnić się, że taki atak typu replay nie zadziała, zwykle pozwalając klientowi wybrać kilka losowych bitów, które są zaszyfrowane wraz z hasłem , a także przesłany w jawnej wersji na serwer.

Na serwerze:

  • wygenerować kilka losowych bitów
  • wyślij te bity (zwykłym tekstem) do klienta

Na kliencie:

  • wygeneruje kilka losowych bitów
  • hasło konkatenacji, losowe bity serwera i losowe bity klienta
  • generuje hash powyższego
  • przesłać losowe bity (w postaci zwykłego tekstu) i hash na serwer

Ponieważ serwer zna własne losowe informacje, a także losowe bity klienta (otrzymał je jako zwykły tekst), może wykonać zasadniczo tę samą transformację. Protokół ten zapewnia, że ​​nikt nasłuchujący tej rozmowy nie będzie mógł później wykorzystać tych informacji do fałszywego uwierzytelnienia przy użyciu zapisanych informacji (chyba że zastosowano bardzo słaby algorytm ...), o ile obie strony za każdym razem generują różne „bity szumu”, wykonywany jest uścisk dłoni.

Edytuj Wszystko to jest podatne na błędy, żmudne i nieco trudne do poprawienia (czytaj: bezpieczne). Jeśli to możliwe, rozważ użycie implementacji protokołów uwierzytelniania już napisanych przez kompetentnych ludzi (w przeciwieństwie do mnie! Powyższe pochodzi tylko z pamięci książki, którą czytałem jakiś czas temu). Naprawdę nie chcesz pisać tego samemu.

Sztylet
źródło
6
Jak może uwierzytelnić się za pomocą zaszyfrowanego hasła w systemie logowania, skoro zostanie ono ponownie zaszyfrowane?
Zakaria
4
Jeśli przechowujesz swoje hasła w postaci zaszyfrowanej na serwerze (tak jak powinieneś), to klient będzie musiał dwukrotnie haszować hasło: najpierw samo hasło, aby pasowało do widoku świata na serwerze, a następnie zgodnie z opisem powyżej dla ze względu na protokół.
Dirk
3
@Dirk, ponieważ napastnik może węszyć w obie strony, „losowe bity” byłyby podsłuchiwane. Następnie osoba atakująca może przeanalizować (czytaj: brutalną siłę) połączenie żądania i odpowiedzi w trybie offline, aby znaleźć oryginalne hasło.
Pacerier,
8
Jednak w celu przesłania hasła lub skrótu hasła często stosuje się asymetryczny proces, taki jak Diffie-Hellman, w celu ustalenia klucza szyfrowania, który umożliwia obu stronom wymianę informacji bez możliwości ich odszyfrowania przez stronę szpiegującą. Dokładnie to robi SSL i jest to powód, dla którego większość witryn ma swoje strony logowania na HTTPS / SSL. SSL już chroni przed atakami typu replay. Zalecałbym korzystanie z SSL zamiast budowania własnego protokołu. Chociaż zgadzam się z haszowaniem + haszowaniem hasła po stronie klienta, ale wysyłam je przez ustanowione połączenie SSL.
AaronLS
15
Dla jasności: jeśli nie używasz HTTPS, nie ma znaczenia, jaki javascript uruchomisz na kliencie; MITM mógłby modyfikować zawartość Twojej strony, zanim trafi ona na klienta. HTTPS to jedyne rozwiązanie.
aidan
62

Przede wszystkim NIE poprawia to bezpieczeństwa Twojej aplikacji (zakładając, że jest to aplikacja internetowa).

Używaj SSL (a właściwie TLS, który jest powszechnie nazywany SSL), nie jest zbyt drogi (zmierz czas poświęcony na znalezienie sposobu na obejście tego problemu i pomnóż go przez minimalną płacę, zakup certyfikatu prawie zawsze wygrywa).

Dlaczego jest to proste. TLS rozwiązuje problem (gdy jest używany z zakupionymi certyfikatami, a nie z podpisem własnym), który jest dość duży w kryptografii: Skąd mam wiedzieć, że serwer, z którym rozmawiam, jest serwerem, z którym rozmawiam? Certyfikaty TLS to sposób na powiedzenie: „Ja, urząd certyfikacji zaufany przez Twoją przeglądarkę, zaświadczam, że witryna internetowa pod adresem [url] ma ten klucz publiczny z odpowiednim kluczem prywatnym, który (klucz prywatny) zna tylko serwer. Podpisałem swój podpis na całym dokumencie, jeśli ktoś go zmienił, widać ”.

Bez TLS każde szyfrowanie staje się bezcelowe, ponieważ jeśli usiądę obok ciebie w kawiarni, mogę sprawić, że twój laptop / smartfon pomyśli, że jestem serwerem, a MiTM (Man in The Middle) ty. Dzięki TLS Twój laptop / smartfon będzie krzyczał „NIEUFANE POŁĄCZENIE”, ponieważ nie mam certyfikatu podpisanego przez urząd certyfikacji, który pasuje do Twojej witryny. (Szyfrowanie a uwierzytelnianie).

Zastrzeżenie: użytkownicy zwykle klikają bezpośrednio te ostrzeżenia: „Niezaufane połączenie? Co? Chcę tylko zdjęcia kociąt! Dodaj wyjątek Kliknij Potwierdź Kliknij TAK! Kocięta!”

Jeśli jednak naprawdę nie chcesz kupować certyfikatu, nadal wdrażaj haszowanie javascript po stronie klienta (i używaj do tego biblioteki standford (SJCL), NIGDY NIE WDRAŻAJ CRYPTO SAM ).

Czemu? Ponowne użycie hasła! Mogę łatwo ukraść plik cookie sesji (co pozwala mi udawać, że jestem Tobą) bez protokołu HTTPS (patrz firesheep). Jeśli jednak dodasz javascript do swojej strony logowania, który przed wysłaniem hashuje twoje hasło (użyj SHA256 lub jeszcze lepiej, użyj SHA256, wyślij im wygenerowany klucz publiczny, a następnie zaszyfruj zaszyfrowane hasło za jego pomocą, nie możesz użyć soli z tym), a następnie wysyła zaszyfrowane / zaszyfrowane hasło do serwera. REHASH hash na swoim serwerze z solą i porównaj to z tym, co jest przechowywane w Twojej bazie danych (zapisz hasło w ten sposób:

(SHA256(SHA256(password)+salt))

(zapisz sól również jako tekst jawny w bazie danych)). I wyślij swoje hasło w ten sposób:

RSA_With_Public_Key(SHA256(password))

i sprawdź swoje hasło w ten sposób:

if SHA256(RSA_With_Private_Key(SHA256(sent_password))+salt_for_username) == stored_pass: login = ok

Ponieważ, JEŻELI ktoś węszy Twojego klienta, będzie mógł zalogować się jako Twój klient (przechwytywanie sesji), ale NIGDY nie zobaczy hasła w postaci zwykłego tekstu (chyba że zmienią Twój javascript, jednak haker Starbucks prawdopodobnie nie będzie wiedział, jak to zrobić / będzie zainteresowany w tym.) Dzięki temu uzyskają dostęp do Twojej aplikacji internetowej, ale nie do swojego adresu e-mail / Facebooka / itp. (do którego użytkownicy prawdopodobnie będą używać tego samego hasła). (Adres e-mail będzie nazwą użytkownika lub będzie można go znaleźć w profilu / ustawieniach aplikacji internetowej).

FriendlyCryptoNeighbor
źródło
1
Myślę, że to dobra odpowiedź, ale prawdopodobnie potrzebuje więcej informacji na temat prawidłowego solenia i że lepiej jest użyć "powolnej" funkcji haszującej przed zapisaniem hasła na serwerze (np. Bcrypt).
Neyt
Tak, zamiast bezpośrednio używać SHA256, użyj bcrypt lub nawet bezpieczniejszej implementacji argon2.
T. Salim
24

Prawdopodobnie nie musisz się tym martwić - jak wspomina Dirk, nawet jeśli haszujesz hasła, złośliwy użytkownik może być w sieci i zobaczyć, że hash został wysłany i może po prostu wysłać ten sam hash.

Jest nieco lepsze, ponieważ uniemożliwia złośliwemu użytkownikowi poznanie hasła, ale ponieważ nadal może się zalogować (lub potencjalnie zrekonstruować oryginalne hasło ), nie jest to zbyt pomocne.

Ogólnie rzecz biorąc, jeśli obawiasz się o bezpieczeństwo haseł i danych użytkownika (a powinieneś!), Będziesz chciał użyć bezpiecznego serwera SSL. Jeśli nie jest to dla Ciebie problemem z jakiegokolwiek powodu, równie dobrze możesz nie zawracać sobie głowy haszowaniem; to tylko bezpieczeństwo poprzez ciemność .


Edycja sierpnia 2014: Google coraz mocniej naciska na witryny internetowe, aby wszędzie przełączały się na HTTPS , ponieważ zabezpieczenie samej komunikacji jest jedynym sposobem zapobiegania atakom podsłuchiwania sieci. Próby zaciemnienia przesyłanych danych tylko utrudniają, a nie zatrzymują, dedykowanego napastnika i mogą dać programistom niebezpieczne fałszywe poczucie bezpieczeństwa.

dimo414
źródło
Myślę, że twoja opinia, że ​​haszowanie po stronie klienta jest tylko "trochę lepsze", jest prawdziwe, jeśli koncentrujesz się wyłącznie na uzyskaniu xhasła użytkownika i dostępie do pojedynczej usługi. Jeśli weźmie się pod uwagę efekt zbiorowy, powiedziałbym, że jest „znacznie lepszy”; ponieważ uniemożliwia tworzenie dużych baz danych wyszukiwania haseł używanych do brutalnej siły solonych skrótów w wielu usługach. IMO. Zobacz, co robi AWS Cognito w kliencie w celach informacyjnych.
f1lt3r
18

Właściwie nie zgadzam się, że haszowanie po stronie klienta jest w tym przypadku bezpieczniejsze. Myślę, że jest mniej bezpieczny.

Cały sens przechowywania skrótu hasła w twojej bazie danych w przeciwieństwie do prawdziwego hasła (lub nawet zaszyfrowanego hasła) polega na tym, że matematycznie niemożliwe jest uzyskanie oryginalnego hasła z hasha (chociaż teoretycznie jest możliwe uzyskanie kolidującego hash input, którego trudność zależy od siły bezpieczeństwa algorytmu haszującego). Możliwym wektorem ataku jest tutaj to, że gdyby potencjalny napastnik w jakiś sposób złamał Twoją bazę danych przechowywania haseł, nadal nie byłby w stanie uzyskać oryginalnych haseł użytkowników.

Jeśli twój mechanizm uwierzytelniania wysyła hash hasła, to w tym scenariuszu naruszenia bezpieczeństwa atakujący nie musi znać prawdziwego hasła - po prostu wysyła hash, który ma i hej, presto, ma dostęp do konta konkretnego użytkownika, a co za tym idzie, cały system. To całkowicie eliminuje sens przechowywania zaszyfrowanego hasła w pierwszej kolejności!

Naprawdę bezpiecznym sposobem na to jest wysłanie klientowi jednorazowego klucza publicznego w celu zaszyfrowania hasła, a następnie odszyfrowanie i ponowne zaszyfrowanie go po stronie serwera.

Nawiasem mówiąc, tego rodzaju pytania prawdopodobnie otrzymają więcej odpowiedzi ekspertów na temat Security StackExchange.

Adam Burley
źródło
3
Całkowicie się z tym zgadzam. Aby podejść do pracy po stronie klienta, należałoby również wysłać sól do klienta, co unieważniłoby cały cel solenia!
James Wright,
@JamesWright: Chodzi o wysyłanie losowej soli przy każdym użyciu, co zapobiega nielegalnemu ponownemu wykorzystywaniu wiadomości logowania. (Forma powtórek ataków). Wysyłanie za każdym razem tej samej soli jest rzeczywiście bezcelowe.
MSalters
Musisz użyć „nonce” ( en.wikipedia.org/wiki/Cryptographic_nonce ). W ten sposób serwer kontroluje również sól i zapewnia to bezpieczeństwo. Haszowanie po stronie klienta jest również ważne, aby wstrzyknięty kod JS nie mógł go później łatwo znaleźć. Więcej tutaj: stackoverflow.com/a/21716654/43615
Thomas Tempelmann
Informacje na temat używania salt + nonce w procesie uwierzytelniania logowania można znaleźć w odpowiedzi: stackoverflow.com/a/24978909/43615
Thomas Tempelmann
Oczywiście, jeśli zaszyfrujesz go po stronie klienta, będziesz musiał ponownie zaszyfrować go po stronie serwera, aby uniknąć tego, co robisz. Jak jednak podkreślają inni, dla zachowania prywatności potrzebujesz już szyfrowania po stronie klienta.
Daniel Methner
5

Pamiętaj, że zabezpieczenie haseł przed osobami trzecimi to nie wszystko.

Gdy tylko w grę wchodzi prywatność (a czy w dzisiejszych czasach nie jest to prawda?) , Nie chcesz znać hasła. Nie możesz nadużywać ani ujawniać tego, czego nie masz , więc zarówno Ty, jak i Twoi klienci możecie spać lepiej, jeśli nigdy nie zobaczycie ich haseł w postaci zwykłego tekstu.

Dlatego haszowanie / szyfrowanie po stronie klienta ma sens.

Raphael
źródło
Zgoda! Wiele osób nie rozumie tego punktu. Jeśli pobiorę Twoją bazę haseł zawierającą zasolone, zaszyfrowane hasła i uda mi się złamać tylko jedną za pomocą bazy danych wyszukiwania skrótów, są szanse, że uda mi się złamać je wszystkie. Kiedy mam 50 000 oryginalnych haseł, mam teraz klucz do xużytkowników w nusługach, które szyfrują tylko na serwerze. Jeśli każda usługa unikatowo szyfruje hasło przed opuszczeniem klienta, duża baza danych haseł między usługami staje się znacznie, dużo mniejsza. Sprawdź ruch logowania AWS, zobacz, co robią. To prawdopodobne, mój drogi Watsonie.
f1lt3r
3

To zależy, możesz użyć haszowania po stronie klienta, ale sól po stronie serwera nie będzie możliwa.

spójrz na link Szyfrowanie hasła po stronie klienta

SmAxlL
źródło
1

Ostatnio dużo nad tym pracowałem, IRL są dwa problemy z hashem / szyfrowaniem symetrycznym po stronie klienta, które naprawdę zabijają ten pomysł: 1. Musisz odzyskać sól z powrotem na serwer SOMEHOW ... i zaszyfrować po stronie klienta potrzebujesz hasła ... które jest sprzeczne z celem. 2. Ujawniasz swoją implementację haszowania (nie jest to WIELKA oferta, ponieważ większość witryn używa jednego z 3 lub 4 algorytmów haszujących), co ułatwia atak (wystarczy spróbować jednego zamiast n).

Ostatecznie poszedłem do asymetrycznego szyfrowania na kliencie przy użyciu OpenPGP.js lub podobnego ... Opiera się to na zaimportowanym lub wygenerowanym przez klienta kluczu na kliencie i serwerze wysyłającym swój klucz publiczny. Na serwer można odesłać tylko klucz publiczny klienta. Chroni to przed atakami MIM i jest tak samo bezpieczne jak urządzenie (obecnie domyślnie przechowuję klucz prywatny klienta w localStore, jest to wersja demonstracyjna).

GŁÓWNĄ zaletą tego jest to, że nigdy nie muszę przechowywać danych użytkowników / nawet w pamięci niezaszyfrowanych na moim serwerze / magazynie danych (a klucz prywatny mojego serwera jest fizycznie oddzielny)

Podstawą tego było zapewnienie ludziom sposobu bezpiecznej komunikacji tam, gdzie HTTPS był ograniczony (np. Iran / Korea Północna itp.), A także po prostu zabawny eksperyment.

Jestem DALEKO od pierwszego, który o tym pomyślał, http://www.mailvelope.com/ używa tego

ScottGal
źródło
1

Jeśli ktoś może zobaczyć dane przychodzące i wychodzące w Twoim połączeniu, uwierzytelnianie Cię nie uratuje. Zamiast tego zrobiłbym następujące dla super tajnych rzeczy.

Hasła wstępnie zhasowane po stronie klienta przed wysłaniem na serwer. (Serwer przechowuje kolejną zaszyfrowaną i zasoloną wartość tego skrótu wysłanego z przeglądarki).

Tak więc atak pośrednika mógłby pozwolić im na wysłanie tej samej wartości hashowanej do logowania co oni, ale hasło użytkownika nie byłoby znane. To powstrzymałoby ich przed próbowaniem innych usług z tymi samymi poświadczeniami w celu zalogowania się w innym miejscu.

Dane użytkowników są również szyfrowane po stronie przeglądarki.

Ach, więc atak pośrednika pozwoliłby uzyskać zaszyfrowane dane, ale nie byłby w stanie ich odszyfrować bez rzeczywistego hasła używanego do logowania. (hasło użytkownika przechowywane w DOM w przeglądarce podczas logowania). Zatem rzeczywisty użytkownik zobaczy odszyfrowaną zawartość, ale środkowy nie. Oznacza to również, że żadna NSA ani inna agencja nie będą w stanie zażądać od Ciebie / firmy / dostawcy usług hostingowych o odszyfrowanie tych danych, ponieważ byłoby to dla nich niemożliwe.

Kilka małych przykładów obu tych metod znajduje się na moim blogu http://glynrob.com/javascript/client-side-hashing-and-encryption/

GlynRob
źródło
1

Niedawno GitHub i Twitter ogłosiły, że hasła są przechowywane w wewnętrznych dziennikach. Zdarzało się to nieumyślnie w raportach błędów i innych dziennikach, które znalazły się w splunku itp. W przypadku Twittera, jeśli hasło Trumpa było w tym dzienniku, administrator może zobaczyć coś wielkiego, a inne strony prawdopodobnie nie tak wielka sprawa, ponieważ administratorzy nie mieliby z tego zbyt wiele pożytku. Niezależnie od tego, że jesteśmy administratorami, nie lubimy widzieć haseł.

Tak więc pytanie brzmi tak naprawdę, czy haszowanie powinno nastąpić po stronie klienta ze względów bezpieczeństwa, ale jak możemy chronić hasło, zanim zostanie ono ostatecznie zaszyfrowane i porównane po stronie serwera, aby w jakiś sposób nie zostało zarejestrowane.

Szyfrowanie nie jest złym pomysłem, ponieważ programiści muszą przynajmniej przeskoczyć przez kilka kółek, a jeśli okaże się, że hasła dostały się do dzienników, możesz po prostu zmienić klucz szyfrowania, zniszczyć oryginał, a dane stają się bezużyteczne. Jeszcze lepiej obracaj klucze co noc i może to znacznie zmniejszyć okna.

Możesz również zaszyfrować skrót w swoim rekordzie użytkownika. Hasła, które wyciekły, byłyby zaszyfrowanymi hasłami w postaci zwykłego tekstu. Serwer przechowuje zahaszowaną wersję skrótu. Jasne, hash staje się hasłem, ale jeśli nie masz pamięci fotograficznej, nie będziesz pamiętać 60-znakowego bcyrpt. Sól z nazwą użytkownika. Jeśli możesz zebrać informacje o użytkowniku podczas procesu logowania (nie ujawniając, że rekord użytkownika istnieje), możesz to również zrobić, tworząc solidniejszy skrót, którego nie można udostępniać między witrynami. Żaden człowiek w środku nie byłby w stanie po prostu wyciąć i wkleić przechwyconego skrótu między witrynami.

Połącz z plikiem cookie, który nie zostanie przesłany z powrotem na serwer, a możesz być na czymś. Na pierwsze żądanie wyślij plik cookie do klienta z kluczem, a następnie upewnij się, że plik cookie nie wraca do usługi logowania, tak więc prawdopodobieństwo jego zalogowania jest niewielkie. Przechowuj klucz w magazynie sesji, a następnie usuń go zaraz po zalogowaniu lub po wygaśnięciu sesji ... wymaga to stanu dla was, chłopaki JWT, ale może po prostu użyj do tego usługi nosql.

Tak więc po drodze administrator napotyka jedno z tych zahaszowanych i zaszyfrowanych haseł w splunku lub narzędziu do zgłaszania błędów. Powinno być dla nich bezużyteczne, ponieważ nie mogą już znaleźć klucza szyfrowania, a nawet jeśli to zrobili, muszą brutalnie wymusić skrót. Ponadto użytkownik końcowy nie wysłał nic w postaci zwykłego tekstu wzdłuż linii, więc każdy człowiek w środku ma przynajmniej trudniejsze chwile i nie można po prostu przeskoczyć do innej witryny i zalogować się.

Eric Twilegar
źródło
Dokładnie moja troska. Jeśli serwer w jakiś sposób loguje się przypadkowo z powodu złej implementacji lub złośliwego zamiaru, możliwe jest, że inne konto użytkownika może zostać przejęte, jeśli ponownie użyje haseł.
Dan
0

Rozważ to:-

Klient wysyła żądanie do serwera „Mam hasło do weryfikacji”.

Serwer wysyła klientowi jednorazowy, losowy ciąg znaków. R $

Klient osadza hasło użytkownika w tym ciągu (na podstawie dowolnych (zmiennych) reguł, które chcesz zastosować).

Klient wysyła ciąg do serwera i jeśli hasło jest prawidłowe, serwer loguje użytkownika.

Jeśli serwer otrzyma kolejne żądanie logowania przy użyciu R $, użytkownik zostanie wylogowany, a konto zostanie zawieszone do czasu dochodzenia.

Oczywiście zostaną podjęte wszystkie inne (normalne) środki ostrożności.

cneeds
źródło
0

Ta idea hashowania po stronie klienta ma na celu ochronę użytkownika, a nie witryny. Jak już wielokrotnie wspomniano, zwykły tekst lub zaszyfrowane hasła mają równy dostęp do Twojej witryny. Nie otrzymujesz korzyści w zakresie bezpieczeństwa.

Jednak rzeczywiste, tekstowe hasło użytkowników powinno być znane tylko im. Wiedza o tym, jakie hasło wybrali, to informacje, które można wykorzystać przeciwko nim w innych witrynach i systemach. Jesteś witryną zorientowaną na klienta, chroniąc go przed ujawnieniem wyboru hasła przez programistów serwera lub osoby trzecie.

n8isjack
źródło