Wie sende ich ein Passwort sicher über HTTP?

115

Wenn ein Benutzer auf einem Anmeldebildschirm ein Formular mit seinem Benutzernamen und Passwort sendet, wird das Passwort im Klartext gesendet (auch mit POST korrigieren Sie mich, wenn ich falsch liege).

Die Frage ist also, wie der Benutzer und sein Passwort richtig vor Dritten geschützt werden können, die möglicherweise die Kommunikationsdaten abhören.

Mir ist bekannt, dass HTTPS eine Lösung für das Problem darstellt. Gibt es jedoch eine Möglichkeit, mithilfe des Standard-HTTP-Protokolls (POST-Anforderung) zumindest ein gewisses Maß an Sicherheit zu gewährleisten? (Vielleicht mit Javascript in irgendeiner Weise)

BEARBEITEN Ich habe möglicherweise einige wichtige Dinge ausgelassen.

Worum es mir ging, war eine Seite - das ist eine von PHP generierte Anmeldeseite, die natürlich in einer HTTP-GET-Anfrage als HTML-Datei an den Benutzer gesendet wird. Es wurde keine (@ Jeremy Powel) Verbindung zwischen dem Server und dem Client hergestellt, daher kann ich kein solches Handshake-Protokoll erstellen. Und ich möchte, dass der gesamte Prozess für den Benutzer transparent ist - er möchte ein Passwort senden und sich nicht mit Kryptografie befassen.

Vielen Dank.

Kornelije Petak
quelle
1
Sie werden dies wahrscheinlich nicht erreichen können, ohne dass der Client Kryptografie verwendet, aber der Benutzer muss einen solchen Prozess nicht sehen. Er gibt nur sein Passwort ein und der Code, den Ihr PHP generiert (z. B. Javascript), erledigt alles für Sie.
Jeremy Powell
13
Das von Ihnen beschriebene Problem ist der Grund, warum HTTPS erfunden wurde. Wenn Sie ein Geheimnis an den Client senden, um das Passwort zu verschlüsseln, kann ein Lauscher es auf der Rückreise abhören und das Passwort entschlüsseln.
jnoss
1
S in Ihrem Vorschlag könnte also nur ein Passwort sein (oder Benutzername + Passwort in irgendeiner Weise kombiniert), da dies das einzige "Geheimnis" ist, das der Benutzer hat. Hab ich recht? Die Lösung wäre also wie folgt: - Der Server stellt der HTML-Seite ein verstecktes Formularfeld zur Verfügung. R - Der Benutzer gibt das Passwort ein. Bevor das Passwort gesendet wird, berechnet das Javascript H (R, S) und sendet es an den Server. vielleicht sogar mit AJAX - Der Server berechnet H (R, S) und vergleicht es mit empfangen und sendet eine Antwort auf eine Ajax-Anfrage, ob die Authentifizierung bestanden wurde - Das Javascript leitet den Browser zur gewünschten Webseite weiter
Kornelije Petak
2
@jeremy powell - Während das, was Sie beschreiben, gängige Praxis ist, ist es auch anfällig für einen Vermittler, der das Cookie aus einem Header schnüffeln und sich durch Wiederverwendung des Cookies als Benutzer ausgeben kann. Man in the Middle-Angriffe sind schwer zu verhindern, es sei denn, Sie verwenden HTTPS
jnoss
1
Für alle, die in Zukunft auf diese Frage kommen: NACH dem Anmelden müssen Sie auch das Sitzungscookie sichern. (Also: die Verwendung von HTTPS ist wirklich viel einfacher.)
Arjan

Antworten:

66

Die Verwendung von HTTP mit SSL erleichtert Ihnen das Leben erheblich und Sie können sich beruhigt ausruhen. Sehr kluge Leute (zumindest schlauer als ich!) Haben diese Methode der vertraulichen Kommunikation jahrelang überprüft.

Jeremy Powell
quelle
14
... und "Aber ich muss für ein SSL-Zertifikat bezahlen !!" ist keine gültige Beschwerde, da Sie sie heutzutage für 30 US-Dollar erhalten können. Sind Ihre Daten wirklich nicht 30 Dollar wert, um sie zu schützen?
Café
3
Was passiert, wenn der von Ihnen abonnierte Webhost das Hinzufügen von SSL-Zertifikaten nicht unterstützt?
Calmarius
89
@ Calmarius - dann wechseln Sie zu einem echten Webhost
BornToCode
3
@BornToCode Dies bedeutet technisch gesehen, dass Sie eine dedizierte IP-Adresse benötigen und die Serverhardware (oder mindestens einen VPS) besitzen müssen, um HTTPS verwenden zu können. Freigegebene Webhosts können kein HTTPS ausführen, es sei denn, der gesamte Server ist mit dem Zertifikat des Hostbesitzers geschützt.
Calmarius
6
freigegebene Webhosts können sicherlich https tun, indem sie en.wikipedia.org/wiki/Server_Name_Indication
Brian Minton
39

Sichere Authentifizierung ist ein weites Thema. Kurz gesagt, wie @ jeremy-powell erwähnte, bevorzugen Sie immer das Senden von Anmeldeinformationen über HTTPS anstelle von HTTP. Es wird viele sicherheitsrelevante Kopfschmerzen beseitigen.

TSL / SSL-Zertifikate sind heutzutage ziemlich billig. In der Tat, wenn Sie überhaupt kein Geld ausgeben möchten, gibt es eine kostenlose letsencrypt.org - automatisierte Zertifizierungsstelle.

Sie können noch einen Schritt weiter gehen und caddyserver.com verwenden, das im Hintergrund letsencrypt aufruft.

Nun, sobald wir HTTPS aus dem Weg geräumt haben ...

Sie sollten Login und Passwort nicht über POST-Payload- oder GET-Parameter senden. Verwenden Sie stattdessen einen Autorisierungsheader (Standardzugriffsauthentifizierungsschema), der wie folgt aufgebaut ist:

  • Der Benutzername und das Passwort werden zu einer durch einen Doppelpunkt getrennten Zeichenfolge kombiniert, z. B.: Benutzername: Passwort
  • Die resultierende Zeichenfolge wird mit der RFC2045-MIME-Variante von Base64 codiert, außer nicht auf 76 Zeichen / Zeile beschränkt.
  • Die Autorisierungsmethode und ein Leerzeichen, dh "Basic", werden dann vor die codierte Zeichenfolge gesetzt.

Quelle: Wikipedia: Autorisierungsheader

Es mag etwas kompliziert erscheinen, ist es aber nicht. Es gibt viele gute Bibliotheken, die diese Funktionalität sofort für Sie bereitstellen.

Es gibt einige gute Gründe, warum Sie einen Autorisierungsheader verwenden sollten

  1. Es ist ein Standard
  2. Es ist einfach (nachdem Sie gelernt haben, wie man sie benutzt)
  3. Sie können sich auf URL-Ebene wie folgt anmelden: https://user:[email protected]/login(Chrome konvertiert es beispielsweise automatisch in einen AuthorizationHeader.)

WICHTIG:
Wie von @zaph in seinem Kommentar unten ausgeführt, ist das Senden vertraulicher Informationen als GET-Abfrage keine gute Idee, da sie höchstwahrscheinlich in Serverprotokollen landen.

Geben Sie hier die Bildbeschreibung ein

FullStackForger
quelle
11
Das Problem beim Senden von Anmeldeinformationen (Kennwort) als GET-Parameter besteht darin, dass das Benutzer / Kennwort-Paar wahrscheinlich in Serverprotokollen landet, was keine gute Idee ist. Es ist am besten, Anmeldeinformationen in einem POST zu senden.
Zaph
Ahh ... überhaupt nicht. Der angezeigte Screenshot wurde geändert, um zu veranschaulichen, was in einem Browser geschieht. Sobald Sie die Eingabetaste drücken, wird Ihre URL konvertiert und ein AuthorizationHeader erstellt. Probieren Sie es einfach aus. Protokolle erinnern sauber. Und wenn Sie einen Anruf vom Server aus tätigen (wenn dies das Szenario ist, über das Sie sich Sorgen machen), sollten Sie den Header natürlich programmgesteuert generieren.
FullStackForger
Sie können nicht protokollieren, was Sie nicht sehen können. username:password@urlvom Browser übersetzt in: url+ AuthorizationAnforderungsheader. Was GET-Abfragen betrifft ... wie gesagt, verwenden Sie den Authroziation-Header. Es ist besser.
FullStackForger
2
Sie sprechen den Punkt der Frage nicht an: Schutz sensibler Daten vor Abhören durch den Mann in der Mitte. Der Fokus liegt nicht darauf, einen alternativen und / oder standardisierteren Weg zu finden, um Anmeldeinformationen weiterzugeben, sondern sie über einen unsicheren Kanal zu schützen.
Lord of the Goo
3
Es sollte betont werden, dass diese Lösung nur funktioniert, wenn Sie die Verbindung bereits mit TLS / SSL verschlüsseln. base64 ist keine Verschlüsselung.
Scot
14

Sie können ein Challenge-Response-Schema verwenden. Angenommen, der Client und der Server kennen beide ein geheimes S. Dann kann der Server sicher sein, dass der Client das Kennwort kennt (ohne es preiszugeben), indem er:

  1. Der Server sendet eine Zufallszahl R an den Client.
  2. Der Client sendet H (R, S) zurück an den Server (wobei H eine kryptografische Hash-Funktion wie SHA-256 ist).
  3. Der Server berechnet H (R, S) und vergleicht es mit der Antwort des Clients. Wenn sie übereinstimmen, weiß der Server, dass der Client das Kennwort kennt.

Bearbeiten:

Hier gibt es ein Problem mit der Frische von R und der Tatsache, dass HTTP zustandslos ist. Dies kann erreicht werden, indem der Server ein Geheimnis erstellt, das Q heißt und das nur der Server kennt . Dann geht das Protokoll so:

  1. Der Server generiert eine Zufallszahl R. Er sendet dann an den Client H (R, Q) (der vom Client nicht gefälscht werden kann).
  2. Der Client sendet R, H (R, Q) und berechnet H (R, S) und sendet alles zurück an den Server (wobei H eine kryptografische Hash-Funktion wie SHA-256 ist).
  3. Der Server berechnet H (R, S) und vergleicht es mit der Antwort des Clients. Dann nimmt es R und berechnet (erneut) H (R, Q). Wenn die Client-Version von H (R, Q) und H (R, S) mit der Neuberechnung des Servers übereinstimmt, hält der Server den Client für authentifiziert.

Da H (R, Q) vom Client nicht gefälscht werden kann, fungiert H (R, Q) als Cookie (und könnte daher tatsächlich als Cookie implementiert werden).

Noch eine Bearbeitung:

Die vorherige Bearbeitung des Protokolls ist falsch, da jeder, der H (R, Q) beobachtet hat, in der Lage zu sein scheint, es mit dem richtigen Hash wiederzugeben. Der Server muss sich merken, welche Rs nicht mehr frisch sind. Ich mache diese Antwort, damit ihr sie bearbeiten und etwas Gutes ausarbeiten könnt.

Jeremy Powell
quelle
+1 - Sie müssen die Antwort auf der Clientseite mit Javascript (oder Flash / Silverlight / etc.)
Berechnen
10
Hält den Menschen nicht in der Mitte oder bei Identitätswechselangriffen auf. ZB über WLAN. Scheint so, als würde dies nur ein falsches Sicherheitsgefühl vermitteln, IMO.
Tom Hawtin - Tackline
2
Das schützt vor passiven Angriffen, aber ein Mann in der Mitte kann immer noch angreifen.
Douglas Leeder
7
Außerdem muss der Server das ursprüngliche Passwort kennen.
Douglas Leeder
3
Krypto nicht neu erfinden! (in Produktion)
Bryanph
11

Wenn Ihr Webhost dies zulässt oder Sie mit vertraulichen Daten umgehen müssen, verwenden Sie HTTPS, Punkt. (Es wird oft vom Gesetz afaik vorgeschrieben).

Andernfalls, wenn Sie etwas über HTTP tun möchten. Ich würde so etwas tun.

  1. Der Server bettet seinen öffentlichen Schlüssel in die Anmeldeseite ein.
  2. Der Client füllt das Anmeldeformular aus und klickt auf Senden.
  3. Eine AJAX-Anforderung erhält den aktuellen Zeitstempel vom Server.
  4. Das clientseitige Skript verkettet die Anmeldeinformationen, den Zeitstempel und ein Salt (gehasht aus analogen Daten, z. B. Mausbewegungen, Tastendruckereignisse) und verschlüsselt sie mit der öffentlichen Taste.
  5. Sendet den resultierenden Hash.
  6. Der Server entschlüsselt den Hash
  7. Überprüft, ob der Zeitstempel aktuell genug ist (erlaubt nur ein kurzes Fenster von 5 bis 10 Sekunden). Lehnt die Anmeldung ab, wenn der Zeitstempel zu alt ist.
  8. Speichert den Hash 20 Sekunden lang. Lehnt denselben Hash für die Anmeldung während dieses Intervalls ab.
  9. Authentifiziert den Benutzer.

Auf diese Weise ist das Kennwort geschützt und der gleiche Authentifizierungs-Hash kann nicht wiedergegeben werden.

Informationen zur Sicherheit des Sitzungstokens. Das ist etwas schwieriger. Es ist jedoch möglich, die Wiederverwendung eines gestohlenen Sitzungstokens etwas zu erschweren.

  1. Der Server setzt ein zusätzliches Sitzungscookie, das eine zufällige Zeichenfolge enthält.
  2. Der Browser sendet dieses Cookie bei der nächsten Anfrage zurück.
  3. Der Server überprüft den Wert im Cookie. Wenn er anders ist, wird die Sitzung zerstört, andernfalls ist alles in Ordnung.
  4. Der Server setzt das Cookie erneut mit einem anderen Text.

Wenn also das Sitzungstoken gestohlen wurde und eine Anfrage von einer anderen Person gesendet wird, wird die Sitzung bei der nächsten Anfrage des ursprünglichen Benutzers zerstört. Wenn der Benutzer also aktiv auf der Website surft und häufig auf Links klickt, kommt der Dieb mit dem gestohlenen Token nicht weit. Dieses Schema kann verstärkt werden, indem eine andere Authentifizierung für die vertraulichen Vorgänge erforderlich ist (z. B. Löschen eines Kontos).

BEARBEITEN: Bitte beachten Sie, dass dies MITM-Angriffe nicht verhindert, wenn der Angreifer eine eigene Seite mit einem anderen öffentlichen Schlüssel und Proxy-Anforderungen an den Server erstellt. Um sich davor zu schützen, muss der öffentliche Schlüssel im lokalen Speicher des Browsers oder in der App fixiert sein, um diese Art von Tricks zu erkennen.

Über die Implementierung: RSA ist wahrscheinlich der bekannteste Algorithmus, aber für lange Schlüssel ist es ziemlich langsam. Ich weiß nicht, wie schnell eine PHP- oder Javascript-Implementierung sein würde. Aber wahrscheinlich gibt es schnellere Algorithmen.

Calmarius
quelle
Ist in diesem Fall das Passwort wirklich geschützt? Könnte nicht jemand herausfinden, was gesendet wird, es mit dem öffentlichen Schlüssel entschlüsseln und dann einfach den Zeitstempel aktualisieren, wenn er ihn später verwendet? Vermisse ich etwas
michaellindahl
@michaellindahl asymmetrische Verschlüsselung bedeutet, dass nur der private Schlüssel - der den Server nie verlässt - zum Entschlüsseln verwendet werden kann. Öffentliche Schlüssel können nur zum Verschlüsseln verwendet werden.
Dan Pantry
2
Ein Computer zwischen dem Browser und dem Server kann den öffentlichen Schlüssel auf der Anmeldeseite ändern.
Antti
Vielen Dank für das Teilen Ihrer Methoden, ich fand alles sehr interessant. Der Zeitstempel, der beim Senden von Glaubensbekenntnissen hinzugefügt wird, ist ein guter Fang! Eine Frage zur Verwendung eines zusätzlichen Sitzungscookies, dessen Wert eine zufällige Zeichenfolge ist: Ist wie ein Token nur für die nächste Anforderung?
Victor
4

Ich würde ein serverseitiges und clientseitiges Diffie-Hellman-Schlüsselaustauschsystem mit AJAX oder mehreren Formularübermittlungen verwenden (ich empfehle das erstere), obwohl ich im Internet keine guten Implementierungen davon sehe. Denken Sie daran, dass eine JS-Bibliothek von MITM immer beschädigt oder geändert werden kann. Lokaler Speicher kann verwendet werden, um dies in gewissem Umfang zu bekämpfen.

Nanofarad
quelle
4

Sie können SRP verwenden , um sichere Kennwörter über einen unsicheren Kanal zu verwenden. Der Vorteil ist, dass ein Angreifer die Kennwörter nicht auf einem anderen Server verwenden kann, selbst wenn er den Datenverkehr abhört oder den Server gefährdet. https://github.com/alax/jsrp ist eine Javascript-Bibliothek, die sichere Kennwörter über HTTP im Browser oder auf der Serverseite (über Knoten) unterstützt.

Brian Minton
quelle
1

HTTPS ist so leistungsfähig, weil es asymmetrische Kryptographie verwendet. Mit dieser Art der Kryptografie können Sie nicht nur einen verschlüsselten Tunnel erstellen, sondern auch überprüfen, ob Sie mit der richtigen Person und nicht mit einem Hacker sprechen.

Hier ist Java-Quellcode, der die asymmetrische Verschlüsselung RSA (von PGP verwendet) zur Kommunikation verwendet: http://www.hushmail.com/services/downloads/

Turm
quelle
0

Sie können SSL für Ihren Host verwenden. Es gibt ein kostenloses Projekt für SSL wie letsencrypt https://letsencrypt.org/

mk990
quelle
2
Überprüfen Sie den dritten Satz. (Lesen Sie auch immer andere Antworten, um sicherzustellen, dass Sie kein weniger detailliertes Duplikat hinzufügen.)
Nathan Tuggy
0

Die Verwendung von https klingt hier am besten (Zertifikate sind heutzutage nicht mehr so ​​teuer). Wenn jedoch http erforderlich ist, können Sie eine Beschriftung verwenden - schreiben Sie sie auf der Serverseite und beschreiben Sie sie im Browser des Benutzers (Schlüssel separat senden).

Wir haben dies bei der Implementierung von safevia.net verwendet. Die Anmeldung erfolgt auf Clientseite (Sender / Empfänger), sodass Benutzerdaten weder auf Netzwerk- noch auf Serverebene verfügbar sind.

parvuselephantus
quelle