Welche Best Practices sollten in einem PHP-Anmeldeskript angewendet werden?

27

Ich möchte meine Anmeldeskripte für Kundenwebsites neu schreiben, um sie sicherer zu machen. Ich möchte wissen, welche Best Practices ich in diese implementieren kann. Passwortgeschützte Control Panels sind in Hülle und Fülle vorhanden, aber nur sehr wenige scheinen Best Practices in Bezug auf das Schreiben von Code, die Geschwindigkeit und die Sicherheit zu implementieren.

Ich werde PHP und eine MySQL-Datenbank verwenden.

Früher habe ich md5 verwendet, aber ich sehe, dass sha256 oder sha512 besser wären (zusammen mit sicherem Hash und Salz).

Einige Anmeldeskripte protokollieren die IP-Adresse während der Sitzung oder sogar den Benutzeragenten, aber ich möchte dies vermeiden, da sie nicht mit Proxyservern kompatibel sind.

Ich bin auch ein wenig hinter den Best Practices bei der Verwendung von Sitzungen in PHP 5 zurückgeblieben (das letzte Mal, als ich gelesen habe, war PHP 4), daher wären einige Best Practices für diese hilfreich.

Vielen Dank.

baritoneuk
quelle
1
Werfen Sie Ihr Skript auf codereview.SE!
Chris
@Chris CodeReview hilft bei der Code-Klarheit und dergleichen. Sie sollten auf keinen Fall zu ihnen gehen, um sich zu schützen. Wenn überhaupt, werden sie Sie fast immer daran erinnern, Ihre eigenen nicht zu "würfeln", was im Grunde die gleiche Antwort ist, die er in jeder Programmiergemeinschaft auf SE bekommen wird.
Alternatex

Antworten:

21

Der beste Gedanke ist, das Rad nicht neu zu erfinden. Ich verstehe jedoch, dass es in der PHP-Welt schwierig sein kann, eine qualitativ hochwertige Komponente zu finden, die dies bereits tut (auch wenn ich mir ziemlich sicher bin, dass die Frameworks solche Dinge implementieren und ihre Implementierungen bereits getestet, solide, codeüberprüft usw. sind. )

Wenn Sie aus bestimmten Gründen kein Framework verwenden können, finden Sie hier einige Vorschläge:

Sicherheitsrelevante Vorschläge

  • Verwenden Sie PBKDF2 oder Bcrypt, wenn Sie können . Dafür ist es getan.

    Begründung: Beide Algorithmen können den Hashing-Prozess beliebig langsam machen. Genau das möchten Sie beim Hashing von Passwörtern (schnellere Alternativen bedeuten einfachere Brute Force). Im Idealfall sollten Sie die Parameter so anpassen, dass der Prozess auf derselben Hardware mit der Zeit immer langsamer wird, während neue, schnellere Hardware freigegeben wird.

  • Wenn dies nicht möglich ist, verwenden Sie mindestens MD5 / SHA1 nicht. Noch nie. Vergiss es . Verwenden Sie stattdessen beispielsweise SHA512. Verwenden Sie auch Salz.

    Begründung: MD5 und SHA1 sind zu schnell. Wenn der Angreifer Zugriff auf Ihre Datenbank hat, die die Hashes enthält, und über einen (nicht einmal besonders leistungsstarken) Computer verfügt, ist es schnell und einfach, ein Passwort zu erzwingen. Wenn keine Salze vorhanden sind, erhöht sich die Wahrscheinlichkeit, dass der Angreifer das tatsächliche Kennwort findet (was zusätzlichen Schaden verursachen kann, wenn das Kennwort an einer anderen Stelle erneut verwendet wird).

  • Verwenden Sie in PHP 5.5.0 und höher password_hashund password_verify.

    Begründung: Das Aufrufen einer vom Framework bereitgestellten Funktion ist einfach, sodass das Risiko eines Fehlers verringert wird. Bei diesen beiden Funktionen müssen Sie nicht an verschiedene Parameter wie den Hash denken. Die erste Funktion gibt eine einzelne Zeichenfolge zurück, die dann in der Datenbank gespeichert werden kann. Die zweite Funktion verwendet diese Zeichenfolge zur Kennwortüberprüfung.

  • Schützen Sie sich vor Gewalt . Wenn der Benutzer ein falsches Kennwort eingibt, obwohl er vor 0,01 Sekunden bereits ein anderes falsches Kennwort eingegeben hat, ist dies ein guter Grund, das Kennwort zu blockieren. Während die Menschen schnell eingeben können, können sie wahrscheinlich nicht sein , dass schnell.

    Ein weiterer Schutz wäre die Festlegung einer stündlichen Ausfallgrenze. Wenn der Benutzer in einer Stunde 3600 falsche Kennwörter eingegeben hat, 1 Kennwort pro Sekunde, ist es schwer zu glauben, dass dies ein legitimer Benutzer ist.

    Begründung: Wenn Ihre Passwörter unsicher gehasht werden, kann Brute Force sehr effektiv sein. Wenn Kennwörter sicher gespeichert werden, verschwendet Brute Force immer noch die Ressourcen und die Netzwerkbandbreite Ihres Servers und führt zu einer geringeren Leistung für legitime Benutzer. Die Brute-Force-Erkennung ist nicht einfach zu entwickeln und in Ordnung zu bringen, aber für jedes kleine System lohnt es sich auf jeden Fall.

  • Bitten Sie Ihre Benutzer nicht, ihre Passwörter alle vier Wochen zu ändern. Dies ist äußerst ärgerlich und verringert die Sicherheit, da die Post-It-Sicherheit gefördert wird.

    Begründung: Die Idee, dass das System durch das Erzwingen eines Kennwortwechsels alle n Wochen vor brutaler Gewalt geschützt wird, ist falsch. Brute-Force-Angriffe sind in der Regel innerhalb von Sekunden, Minuten, Stunden oder Tagen erfolgreich, sodass monatliche Kennwortänderungen keine Rolle mehr spielen. Andererseits sind Benutzer schlecht darin, sich Kennwörter zu merken. Wenn sie diese ändern müssen, versuchen sie entweder, sehr einfache Passwörter zu verwenden, oder notieren sich ihre Passwörter einfach auf den Post-its.

  • Prüfe alles, jedes Mal. Speichern Sie Anmeldungen, aber niemals Kennwörter im Überwachungsprotokoll. Stellen Sie sicher, dass das Überwachungsprotokoll nicht geändert werden kann (dh Sie können am Ende Daten hinzufügen, die vorhandenen Daten jedoch nicht ändern). Stellen Sie sicher, dass die Überwachungsprotokolle regelmäßig gesichert werden. Im Idealfall sollten Protokolle auf einem dedizierten Server mit sehr restriktiven Zugriffen gespeichert werden: Wenn ein anderer Server gehackt wird, kann der Angreifer die Protokolle nicht löschen, um seine Anwesenheit (und den Pfad, der während des Angriffs verwendet wurde) zu verbergen.

  • Erinnern Sie sich nicht an die Benutzeranmeldeinformationen in Cookies, es sei denn, der Benutzer fragt danach (das Kontrollkästchen "Erinnere dich an mich" muss standardmäßig deaktiviert sein, um menschliches Versagen zu vermeiden).

Benutzerfreundlichkeit Vorschläge

  • Lassen Sie den Benutzer sich das Passwort merken, wenn er möchte, auch wenn die meisten Browser diese Funktion bereits verwenden.
  • Verwenden Sie nicht den Google-Ansatz, wenn der Benutzer nicht nach Benutzername und Kennwort gefragt wird, sondern manchmal nur nach Kennwort . Der Benutzername wird bereits in einem angezeigt <span/>. Browser können in diesem Fall das Kennwortfeld nicht ausfüllen (zumindest Firefox kann dies nicht), sodass eine Abmeldung und eine Anmeldung mit einem normalen Formular erforderlich sind, das vom Browser ausgefüllt wird.
  • Verwenden Sie für die Anmeldung keine mit JavaScript aktivierten Popups . Es bricht Browser Passwort-Funktionen (und saugt in allen Fällen).
  • Lassen Sie den Benutzer entweder ihren Benutzernamen oder ihre E-Mail-Adresse eingeben . Wenn ich mich registriere, ist manchmal der Benutzername, den ich eingeben möchte, bereits vergeben, daher muss ich einen neuen erfinden. Ich habe alle Chancen, diesen Namen in zwei Stunden zu vergessen.
  • Behalten Sie immer einen Link zur Funktion "Passwort vergessen" in der Nähe des Anmeldeformulars. Zeigen Sie es nicht nur an, wenn der Benutzer sich nicht angemeldet hat: Benutzer, die sich an ihr Passwort überhaupt nicht erinnern, haben keine Ahnung, dass sie ein falsches Passwort eingeben müssen, um den Link "Passwort vergessen" zu sehen.
  • Verwenden Sie keine Sicherheit per Post-it .
  • Erfinde keine dummen Regeln für das Passwort, um es schwächer zu machen . Beispiel: "Ihr Passwort muss mit einem Kleinbuchstaben beginnen."; "Ihr Passwort darf keine Leerzeichen enthalten."
Arseni Mourzenko
quelle
Nicht über bcrypt kommen. Was ist Ihre Begründung dafür, das zu empfehlen? Warum nicht md5 / sha1? Danke für den Rest der Vorschläge!
Baritoneuk
Die Argumentation ist einfach: Sie bcryptwird von hochqualifizierten Leuten gemacht. Es wurde auch getestet, überprüft usw. Es gibt also keinen Grund, dasselbe selbst zu implementieren. Es ist wie das Erstellen eines eigenen Kryptografiealgorithmus für Ihre Website. * "Warum nicht md5 / sha1?": Siehe zum Beispiel en.wikipedia.org/wiki/MD5#Security
Arseni Mourzenko
5
bcrypt ist langsam und wird wie erwähnt von Profis implementiert. md5 ist ein Hash-Algorithmus, keine Verschlüsselung, die nicht ganz dasselbe ist. Das schnelle Hashing einer Datei ist gut, hier würde md5 verwendet ... das Hashing eines Passworts muss nicht so schnell sein, bcrypt kann hier Abhilfe schaffen. Grund dafür ist, dass Brute Force schwieriger wird, wenn der Krypto-Algorithmus "langsam" ist.
Chris
2
@baritoneuk: Minimum ist cool. Aber ich kann nicht zählen, wie viele Websites ich besucht habe, bei denen Einschränkungen wie maximale Länge, keine nicht alphanumerischen Zeichen usw. aufgetreten sind , sie speichern es einfach in ihrer Datenbank im Klartext.
Carson63000
1
@ Brian Ortiz: nicht immer. Es ist manchmal eine gute Idee, ein Limit festzulegen. Wenn Sie es nicht tun, testen Sie, ob Ihre Anwendung für eine beliebige Länge funktioniert? Wie? Wie können Sie sicher sein, dass es funktioniert, wenn Sie es nicht testen? Wenn Sie stattdessen ein Limit auf einen vernünftigen Wert wie 100 festlegen, können Sie problemlos ein Kennwort mit 100 Zeichen testen.
Arseni Mourzenko
6
  1. Ihre Site sollte HTTPS verwenden. Sie sollten zu keinem Zeitpunkt eine Anmeldeseite anzeigen oder Anmeldungen von einer unverschlüsselten Verbindung annehmen.
  2. Ihre Cookies sollten auf HTTP und auf sichere Verbindungen beschränkt sein, wenn Sie HTTPS verwenden.
  3. Der Anmeldevorgang sollte nicht weniger als 2 Sekunden dauern (1, wenn Sie denken, dass 2 Sekunden zu lang sind). Verwenden Sie einen sicheren Hash, wenn Sie Kennwörter speichern und überprüfen, und verwenden Sie ein Salz, das schwerer zu erraten ist. Verwenden Sie bcryptwenn möglich. Verwenden Sie andernfalls eine andere Art von iteriertem Hash.
  4. Nie jemals komponieren Sie Ihre Datenbankabfragen in einer Weise , die Funktionen wie unter Verwendung erfordert mysql_real_escape_string. Verwenden Sie niemals Zeichenfolgenverkettung, um Ihre Abfrage zu erstellen. Verwenden Sie vorbereitete, parametrisierte Abfragen. Die meisten, wenn nicht alle DB-Treiber für PHP unterstützen dies. Wenn Sie nicht wissen , wie es zu tun, einige Zeit Lernen verbringen , wie man prepare, bindund executeverwenden Sie das DB Sie verwenden. Es ist die einzige sichere Möglichkeit , sich gegen SQL - Injection zu schützen. PDO unterstützt dies.
  5. Ermutigen Sie Ihre Benutzer, nicht dasselbe Kennwort zu verwenden, das sie für ihre E-Mails verwenden. Erinnern Sie sie daran, dass bei einer Beeinträchtigung Ihrer Website und der Verwendung desselben Kennworts an beiden Stellen eine Person ihre E-Mail-Adresse entführen kann.
greyfade
quelle
+1 für HTTPS, da immer mehr Verkehr über öffentliche WiFi-Netzwerke stattfindet. Aber ich bin nicht einverstanden mit dem Punkt 3: 2 Sekunden ist aus Sicht des Benutzers zu lang. 0,5 s. ist in Ordnung, besonders wenn andere Anti-Brute-Force-Techniken verwendet werden.
Arseni Mourzenko
Ich bin in Punkt 4 verwirrt. Wie entkommt man der Konvention, Daten mit mysql_real_escape_string zu entkommen? Alle vom Benutzer übermittelten Daten sollten nicht vertrauenswürdig sein und entsprechend gefiltert werden.
Chrisw
@chrisw: Ja, alle Benutzereingaben sollten als böswillig behandelt werden. Wenn Sie jedoch parametrisierte Abfragen verwenden, ist dies, abgesehen von keiner, die beste Möglichkeit, die SQL-Injection zu stoppen . Wenn Sie keine vorbereiteten und parametrisierten Abfragen verwenden, sind Sie anfällig für SQL-Injection. mysql_real_escape_stringist falsche Sicherheit - es ist keine Garantie. Parametrisierte Abfragen sind.
greyfade
Ich bin jetzt einverstanden, nachdem ich etwas weiter darin gelesen habe. Die Funktion: mysql_real_escape_string ist im Allgemeinen zum größten Teil sicher, ich würde es nicht als RIESIGE Haftung betrachten, aber ich kann sehen, wie effizienter die Verwendung der vorbereiteten Anweisungen ist.
Chrisw
1
Sie können PDO verwenden.
Felix G
1

Verwenden Sie einen gesalzenen One-Way-Hash (vorzugsweise SHA512 unter http://au2.php.net/manual/en/function.hash.php ) ... auf diese Weise, wenn jemand Ihre Datenbank hackt, auch wenn er das Salt kennt können sie die Passwörter nicht extrahieren (ohne eine Regenbogentabelle, die für SHA512 lang wäre).

Verwenden Sie HTTPS.

Senden Sie dem Benutzer bei der Registrierung keine Benutzernamen- / Passwortbestätigungen per E-Mail zurück.

Wenn Sie Cookies für "Erinnere dich an mich" zulassen, fügen Sie ein zusätzliches Login hinzu, um auf die Administrations- und Profilbearbeitungsfunktionen zuzugreifen.

Wenn ein Benutzer ein falsches Passwort erhält, sagen Sie nicht, dass er das falsche Passwort erhalten hat (sagen Sie, dass er den Benutzernamen oder das falsche Passwort immer erhalten hat) - auf diese Weise erhalten Sie weniger Hinweise darauf, welche Benutzernamen gültig sind.

Versuchen Sie, den Benutzernamen gegenüber der Anmeldung zu implementieren. Auf diese Weise werden weniger Benutzer ihren Anmeldenamen in Benutzerlisten anzeigen.

HorusKol
quelle
Stimmen Sie voll und ganz dem Gedanken zu, keine E-Mails im Klartext per E-Mail zu versenden. Ich habe die Anzahl der Male verloren, die Websites dies tun. Wenn Sie 1 Passwort für alle Websites haben (was ich zum Glück nicht tue), sind möglicherweise alle Websites kompromittiert. Solche Websites speichern Passwörter wahrscheinlich auch im Klartext. seufz
baritoneuk
1
  • Verwenden Sie niemals MD5- oder SHA1-Hashing-Algorithmen. Halten Sie sich immer an neuere wie SHA512
  • Verwenden Sie immer ein stark zufällig erzeugtes Salz
  • Schicken Sie Ihren Benutzern niemals ihre Passwörter per E-Mail, selbst wenn Sie "Passwort vergessen" haben.
  • Verwenden Sie niemals die mysql_ * -Funktionen. Sie sind lange abgeschrieben. Halten Sie sich an die gU
  • Speichern Sie niemals Passwörter in Sitzungen oder Cookies
Robin Thomas
quelle
0

Ein Tipp: Stellen Sie sicher, dass auf Ihre Cookies nicht mit JS zugegriffen werden kann, um Diebstahl zu verhindern. Weitere Informationen finden Sie unter Schutz Ihrer Cookies: Nur HTTP- Artikel von Jeff Atwood

... Durch geschickte Konstruktion schafft es die fehlerhafte URL nur, an dem Desinfektionsmittel vorbei zu quietschen. Wenn der endgültig gerenderte Code im Browser angezeigt wird, wird ein Skript von diesem Remoteserver geladen und ausgeführt.

... wer diese mit Skripten versehene Benutzerprofilseite lädt, hat soeben versehentlich seine Browser-Cookies an einen bösen Remote-Server übertragen!

Wie wir bereits festgestellt haben, hat jemand, der Ihre Browser-Cookies für eine bestimmte Website verwendet, im Wesentlichen die Schlüssel zum Königreich für Ihre Identität dort ...

James
quelle