Jak bezpiecznie wysłać hasło przez HTTP?

115

Jeśli na ekranie logowania użytkownik przesyła formularz ze swoją nazwą użytkownika i hasłem, hasło jest wysyłane zwykłym tekstem (nawet z POST, popraw mnie, jeśli się mylę).

Zatem pytanie brzmi: jaki jest właściwy sposób ochrony użytkownika i jego hasła przed osobami trzecimi, które mogą podsłuchiwać dane komunikacyjne?

Zdaję sobie sprawę, że HTTPS rozwiązuje problem, ale czy istnieje sposób na zapewnienie przynajmniej pewnego poziomu bezpieczeństwa przy użyciu standardowego protokołu HTTP (żądanie POST)? (być może używając w jakiś sposób javascript)

EDYTUJ Mogłem pominąć kilka ważnych rzeczy.

Miałem na myśli stronę - czyli stronę logowania wygenerowaną w PHP, która jest oczywiście wysyłana do użytkownika w żądaniu HTTP GET jako plik HTML. Nie ma połączenia (@Jeremy Powel) między serwerem a klientem, więc nie mogę utworzyć takiego protokołu uzgadniania. I chcę, aby cały proces był przejrzysty dla użytkownika - chce podać hasło, a nie zajmować się kryptografią.

Dzięki.

Kornelije Petak
źródło
1
Prawdopodobnie nie będziesz w stanie tego osiągnąć bez klienta korzystającego z kryptografii, ale użytkownik nie musi widzieć takiego procesu. Po prostu wprowadza swoje hasło, a kod generowany przez PHP (na przykład javascript) obsługuje to wszystko za Ciebie.
Jeremy Powell
13
Problem, który opisujesz, jest przyczyną wynalezienia protokołu HTTPS. Jeśli wyślesz klientowi sekret w celu zaszyfrowania hasła, podsłuchujący będzie mógł go wykryć i odszyfrować hasło w drodze powrotnej.
jnoss
1
Zatem S w twojej sugestii może być tylko hasłem (lub połączeniem nazwy użytkownika i hasła w jakikolwiek sposób), ponieważ jest to jedyny „sekret”, jaki posiada użytkownik. Mam rację? Rozwiązanie byłoby więc następujące: - Serwer udostępnia stronie HTML ukryte pole formularza R - Użytkownik wprowadza hasło, a przed wysłaniem hasła javascript oblicza H (R, S) i wysyła je na serwer, być może nawet przy użyciu AJAX - Serwer oblicza H (R, S) i porównuje je z otrzymanymi i wysyła odpowiedź na żądanie AJAX, czy uwierzytelnienie powiodło się - JavaScript przekierowuje przeglądarkę na żądaną stronę internetową
Kornelije Petak
2
@jeremy powell - chociaż to, co opisujesz, jest powszechną praktyką, jest również podatne na atak pośrednika, który może wywęszyć plik cookie z nagłówka i podszyć się pod użytkownika, wykorzystując go ponownie. Ataki typu Man in the Middle są trudne do zabezpieczenia, chyba że używasz HTTPS
jnoss
1
Dla każdego, kto odpowie na to pytanie w przyszłości: PO zalogowaniu należy również zabezpieczyć plik cookie sesji. (A więc: używanie HTTPS jest o wiele łatwiejsze.)
Arjan

Odpowiedzi:

66

Korzystanie z protokołu HTTP z SSL znacznie ułatwi Ci życie i możesz spać spokojnie. Bardzo mądrzy ludzie (przynajmniej mądrzejsi ode mnie!) Od lat badają tę metodę poufnej komunikacji.

Jeremy Powell
źródło
14
... i „Ale muszę zapłacić za certyfikat SSL !!” nie jest uzasadnioną skargą, ponieważ w dzisiejszych czasach możesz je otrzymać za 30 USD. Czy Twoje dane naprawdę nie są warte 30 dolarów, aby chronić?
kawiarnia
3
Co się stanie, jeśli zasubskrybowany serwer WWW nie obsługuje dodawania certyfikatów SSL?
Calmarius
89
@Calmarius - wtedy przenosisz się na prawdziwego
webhosta
3
@BornToCode To technicznie oznacza, że ​​musisz mieć dedykowany adres IP i musisz posiadać sprzęt serwera (lub przynajmniej VPS), aby korzystać z HTTPS. Współdzielone hosty internetowe nie mogą obsługiwać protokołu HTTPS, chyba że cały serwer jest chroniony certyfikatem właściciela hosta.
Calmarius,
6
współdzielone hosty internetowe z pewnością mogą robić https, używając en.wikipedia.org/wiki/Server_Name_Indication
Brian Minton
39

Bezpieczne uwierzytelnianie to szeroki temat. Krótko mówiąc, jak wspomniał @ jeremy-powell, zawsze preferuj wysyłanie danych uwierzytelniających przez HTTPS zamiast HTTP. Zabierze to wiele bólów głowy związanych z bezpieczeństwem.

Certyfikaty TSL / SSL są obecnie dość tanie. W rzeczywistości, jeśli w ogóle nie chcesz wydawać pieniędzy, istnieje darmowy letsencrypt.org - automatyczny urząd certyfikacji.

Możesz pójść o krok dalej i skorzystać z witryny caddyserver.com, która w tle wywołuje letencrypt.

Teraz, gdy już usunęliśmy HTTPS ...

Nie należy przesyłać loginu i hasła przez ładunek POST lub parametry GET. Zamiast tego użyj nagłówka autoryzacji (schemat uwierzytelniania dostępu podstawowego), który jest zbudowany w następujący sposób:

  • Nazwa użytkownika i hasło są łączone w ciąg oddzielony dwukropkiem, np .: nazwa użytkownika: hasło
  • Wynikowy ciąg jest kodowany przy użyciu wariantu RFC2045-MIME Base64, ale nie jest ograniczony do 76 znaków / wiersz.
  • Metoda autoryzacji i spacja, np. „Basic”, są następnie umieszczane przed zakodowanym ciągiem.

źródło: Wikipedia: nagłówek autoryzacji

Może się to wydawać nieco skomplikowane, ale tak nie jest. Istnieje wiele dobrych bibliotek, które zapewniają tę funkcjonalność zaraz po wyjęciu z pudełka.

Istnieje kilka dobrych powodów, dla których warto użyć nagłówka Authorization

  1. To jest standard
  2. To proste (po nauczeniu się ich obsługi)
  3. Pozwoli ci to zalogować się na poziomie adresu URL, na przykład: https://user:[email protected]/login(Chrome, na przykład, automatycznie przekonwertuje go na Authorizationnagłówek)

WAŻNE:
Jak zauważył @zaph w swoim komentarzu poniżej, wysyłanie poufnych informacji jako zapytania GET nie jest dobrym pomysłem, ponieważ najprawdopodobniej trafią one do dzienników serwera.

wprowadź opis obrazu tutaj

FullStackForger
źródło
11
Problem z wysyłaniem poświadczeń (hasła) jako parametrów GET polega na tym, że para użytkownik / hasło prawdopodobnie trafi do dzienników serwera, co nie jest dobrym pomysłem. Najlepiej jest wysłać poświadczenia w POST.
zaph
Ahh ... wcale. Zrzut ekranu, który widzisz, jest modyfikowany, aby zilustrować, co dzieje się w przeglądarce. W momencie naciśnięcia klawisza Enter przeglądarka przekonwertuje adres URL, tworząc Authorizationnagłówek. Po prostu spróbuj. Dzienniki przypomną czyste. I oczywiście, jeśli dzwonisz z serwera (jeśli jest to scenariusz, o który się martwisz), powinieneś oczywiście programowo wygenerować nagłówek.
FullStackForger
Nie możesz zarejestrować tego, czego nie widzisz. username:password@urlz przeglądarki przekłada się na: url+ Authorizationnagłówek żądania. Jeśli chodzi o zapytania GET ... tak jak powiedziałem, użyj nagłówka Authroziation. To jest lepsze.
FullStackForger
2
Nie odpowiadasz na pytanie: ochrona wrażliwych danych przed podsłuchiwaniem przez człowieka. Celem nie jest znalezienie alternatywnego i / lub bardziej ustandaryzowanego sposobu przekazywania danych uwierzytelniających, ale ochrona ich przez niezabezpieczony kanał.
Lord of the Goo
3
Należy podkreślić, że to rozwiązanie działa tylko wtedy, gdy już szyfrujesz połączenie za pomocą TLS / SSL. base64 nie jest szyfrowaniem.
Scot
14

Możesz użyć schematu odpowiedzi na wyzwanie. Powiedz, że klient i serwer znają sekret S. Następnie serwer może mieć pewność, że klient zna hasło (bez podawania go) przez:

  1. Serwer wysyła losową liczbę R do klienta.
  2. Klient wysyła H (R, S) z powrotem do serwera (gdzie H to kryptograficzna funkcja skrótu, taka jak SHA-256)
  3. Serwer oblicza H (R, S) i porównuje to z odpowiedzią klienta. Jeśli są zgodne, serwer wie, że klient zna hasło.

Edytować:

Występuje tu problem ze świeżością języka R i faktem, że protokół HTTP jest bezstanowy. Można temu zaradzić, każąc serwerowi utworzyć sekret, nazwij go Q, który zna tylko serwer . Następnie protokół wygląda tak:

  1. Serwer generuje losową liczbę R. Następnie wysyła do klienta H (R, Q) (która nie może być sfałszowana przez klienta).
  2. Klient wysyła R, H (R, Q) i oblicza H (R, S) i wysyła to wszystko z powrotem na serwer (gdzie H to kryptograficzna funkcja skrótu, taka jak SHA-256)
  3. Serwer oblicza H (R, S) i porównuje to z odpowiedzią klienta. Następnie bierze R i oblicza (ponownie) H (R, Q). Jeśli wersja H (R, Q) i H (R, S) klienta odpowiada ponownym obliczeniom serwera, serwer uważa, że ​​klient jest uwierzytelniony.

Należy zauważyć, że ponieważ H (R, Q) nie może zostać sfałszowane przez klienta, H (R, Q) działa jako plik cookie (i dlatego może być faktycznie zaimplementowane jako plik cookie).

Kolejna edycja:

Poprzednia edycja protokołu jest nieprawidłowa, ponieważ każdy, kto obserwował H (R, Q), wydaje się być w stanie odtworzyć ją z poprawnym hashem. Serwer musi pamiętać, które R nie są już świeże. Dążę do tej odpowiedzi, więc możecie to zmienić i wypracować coś dobrego.

Jeremy Powell
źródło
+1 - musisz obliczyć odpowiedź po stronie klienta za pomocą javascript (lub Flash / Silverlight / itp.)
orip
10
Nie powstrzymuje człowieka w środku ani ataków podszywania się. Np. Przez wifi. Wygląda na to, że da to fałszywe poczucie bezpieczeństwa, IMO.
Tom Hawtin - tackline
2
To chroni przed pasywnymi atakami, ale człowiek pośrodku może nadal atakować.
Douglas Leeder
7
Ponadto serwer musi znać oryginalne hasło.
Douglas Leeder
3
Nie wymyślaj na nowo kryptowalut! (w produkcji)
bryanph
11

Jeśli Twój host na to pozwala lub będziesz musiał radzić sobie z poufnymi danymi, użyj HTTPS, kropka. (Często jest to wymagane przez prawo).

W przeciwnym razie, jeśli chcesz zrobić coś przez HTTP. Zrobiłbym coś takiego.

  1. Serwer osadza swój klucz publiczny na stronie logowania.
  2. Klient wypełnia formularz logowania i klika Prześlij.
  3. Żądanie AJAX pobiera aktualny znacznik czasu z serwera.
  4. Skrypt po stronie klienta łączy poświadczenia, znacznik czasu i sól (zaszyfrowaną z danych analogowych, np. Ruchy myszy, zdarzenia związane z naciśnięciem klawisza), szyfruje je przy użyciu klucza publicznego.
  5. Przesyła wynikowy skrót.
  6. Serwer odszyfrowuje skrót
  7. Sprawdza, czy sygnatura czasowa jest wystarczająco aktualna (zezwala tylko na krótkie 5-10 sekundowe okno). Odrzuca logowanie, jeśli sygnatura czasowa jest zbyt stara.
  8. Przechowuje hash przez 20 sekund. Odrzuca ten sam skrót do logowania w tym okresie.
  9. Uwierzytelnia użytkownika.

W ten sposób hasło jest chronione i ten sam skrót uwierzytelniania nie może zostać odtworzony.

O bezpieczeństwie tokena sesji. To trochę trudniejsze. Możliwe jest jednak nieco utrudnienie ponownego wykorzystania skradzionego tokena sesji.

  1. Serwer ustawia dodatkowy plik cookie sesji, który zawiera losowy ciąg.
  2. Przeglądarka odsyła ten plik cookie przy następnym żądaniu.
  3. Serwer sprawdza wartość w pliku cookie, jeśli jest inna, niszczy sesję, w przeciwnym razie wszystko jest w porządku.
  4. Serwer ponownie ustawia plik cookie z innym tekstem.

Jeśli więc token sesji zostanie skradziony, a żądanie zostanie wysłane przez kogoś innego, to przy następnym żądaniu pierwotnego użytkownika sesja zostanie zniszczona. Jeśli więc użytkownik aktywnie przegląda witrynę, często klikając w linki, to złodziej nie zajdzie daleko ze skradzionym tokenem. Ten schemat można wzmocnić, wymagając innego uwierzytelnienia dla wrażliwych operacji (takich jak usunięcie konta).

EDYCJA: Należy pamiętać, że nie zapobiega to atakom MITM, jeśli osoba atakująca utworzy własną stronę z innym kluczem publicznym i żądaniami serwerów proxy do serwera. Aby się przed tym zabezpieczyć, klucz publiczny musi być przypięty do lokalnej pamięci przeglądarki lub w aplikacji, aby wykryć tego rodzaju sztuczki.

O implementacji: RSA jest prawdopodobnie najbardziej znanym algorytmem, ale jest dość powolny dla długich kluczy. Nie wiem, jak szybka byłaby implementacja PHP lub Javascript. Ale prawdopodobnie istnieją szybsze algorytmy.

Calmarius
źródło
Czy w takim przypadku hasło jest naprawdę chronione? Czy ktoś nie mógłby wyłowić, co jest wysyłane i odszyfrować go za pomocą klucza publicznego, a następnie zaktualizować sygnaturę czasową, gdy użyje go później? Czy coś mi brakuje?
michaellindahl
Asymetryczne szyfrowanie @michaellindahl oznacza, że ​​tylko klucz prywatny - który nigdy nie opuszcza serwera - może być użyty do odszyfrowania rzeczy. Klucze publiczne mogą być używane tylko do szyfrowania.
Dan Pantry
2
Komputer między przeglądarką a serwerem mógłby zmienić klucz publiczny na stronie logowania.
Antti
Dzięki za podzielenie się swoimi metodami, znalazłem bardzo interesujące wszystko. Znacznik czasu dodany przy wysyłaniu danych uwierzytelniających to dobry chwyt! Jedno pytanie na temat używania dodatkowego pliku cookie sesji, którego wartością jest losowy ciąg: jest jak token tylko dla następnego żądania?
Victor
4

Użyłbym systemu wymiany kluczy Diffie-Hellman po stronie serwera i klienta z AJAX lub wieloma przesyłaniami formularzy (polecam ten pierwszy), chociaż nie widzę żadnych dobrych implementacji w Internecie. Pamiętaj, że biblioteka JS zawsze może zostać uszkodzona lub zmieniona przez MITM. W pewnym stopniu można skorzystać z pamięci lokalnej, aby temu zaradzić.

nanofarad
źródło
4

Możesz użyć SRP, aby używać bezpiecznych haseł na niezabezpieczonym kanale. Zaletą jest to, że nawet jeśli atakujący podsłuchuje ruch lub włamie się do serwera, nie może użyć haseł na innym serwerze. https://github.com/alax/jsrp to biblioteka javascript obsługująca bezpieczne hasła przez HTTP w przeglądarce lub po stronie serwera (przez węzeł).

Brian Minton
źródło
1

HTTPS jest tak potężny, ponieważ wykorzystuje kryptografię asymetryczną. Ten rodzaj kryptografii pozwala nie tylko stworzyć zaszyfrowany tunel, ale także zweryfikować, czy rozmawiasz z właściwą osobą, a nie z hakerem.

Oto kod źródłowy Java, który wykorzystuje asymetryczny szyfr RSA (używany przez PGP) do komunikacji: http://www.hushmail.com/services/downloads/

wieża
źródło
0

możesz użyć ssl dla swojego hosta istnieje darmowy projekt dla ssl, taki jak letsencrypt https://letsencrypt.org/

mk990
źródło
2
Zaznacz trzecie zdanie, o którym mowa. (Zawsze czytaj też inne odpowiedzi, aby upewnić się, że nie dodajesz mniej szczegółowego duplikatu).
Nathan Tuggy
0

Korzystanie z protokołu HTTPS brzmi tutaj najlepiej (certyfikaty nie są obecnie takie drogie). Jeśli jednak wymagany jest http, możesz użyć szyfrowania - zaszyfrować go po stronie serwera i odszyfrować w przeglądarce użytkownika (wyślij klucz osobno).

Wykorzystaliśmy to przy implementacji safevia.net - kodowanie odbywa się po stronie klienta (nadawcy / odbiorcy), więc dane użytkowników nie są dostępne w warstwie sieciowej ani serwerowej.

parvuselephantus
źródło