Portal > Foren > Ankündigungen, News und Feedback > Tutorials > [php] Passwörter sicher speichern
Thema geschlossen
 
LinkBack Themen-Optionen Thema durchsuchen
Alt 13.01.2009, 14:27 Nach oben    #1
Projektleiter
 
Registriert seit: 30.11.2005
Ort: Bottrop
Beiträge: 1.365
Standard [php] Passwörter sicher speichern

Ein Bereich, der bei der Entwicklung eines Login-Systems leider häufig viel zu kurz kommt, ist das Speichern der Benutzer-Passwörter. Der "aktuelle" Stand der Dinge ist die Passwörter mithilfe von md5 (oder, mit etwas Glück als sha1) gehashed zu speichern.

Grundlagen des Hashing
Als Hashing wird ein Prozess bezeichnet, der eine Eingabe X zu einer Ausgabe Y übersetzt:
Code:
h:X -> Y
Dabei ist es üblich, dass für Y einige Konditionen gelten. Y ist, genau wie X, eine Zeichenkette. Meistens hat Y eine feste Länge. Bei md5 sind das z.B. 32 Zeichen, bestehend aus den Zeichen 0-9 und A-F (Hexadezimal-System).
Am wichtigsten ist aber, dass es keine Möglichkeit gibt, von einem gegebenem Y zum ursprünglichen X zu kommen. Dadurch ist es Dieben unmöglich, herauszufinden, welches Passwort ein Benutzer verwendet hat, selbst wenn sie den hash zur Verfügung haben.
Leider ist das nicht das Ende der Geschichte, denn Hashing hat ein sehr großes Problem: Eine unendliche Menge von Eingaben X wird auf eine endliche Menge Ausgaben Y übersetzt.
Klingt kompliziert? Ist aber ganz einfach. Es gibt unendlich viele X (ich kann ja an jedes beliebige X einfach noch ein paar Zeichen anhängen), aber aufgrund der fixen Länge von Y und des begrenzten Alphabets nur eine begrenzte Menge an Ausgaben (ich kann mit einer fixen Menge an Zeichen auf eine fixe Länge gesehen keine unendlichen Kombinationen herstellen). Daraus folgt dann aber, dass es mehrere verschiedene X geben muss, die zum gleichen Y übersetzt werden:
Code:
h(x1) = h(x2)
md5/sha1 sind unsicher
Diese Gleichheit wird als "Kollision" bezeichnet. Viele Hashing-Algorithmen betrifft das Problem (noch) nicht, weil sich keine gezielten Kollisionen herstellen lassen. Das gilt leider nicht mehr für md5 und auch sha1 gilt aus diesem Grund als nicht mehr sicher.
Bei md5 ist es inzwischen möglich von einem Text ausgehend einen anderen Text zu erzeugen, der den gleichen Hash-Code hat. Der Weg von Hash zu Text (irgendeinem Text, der diesen Hash erzeugt, nicht unbedingt dem Ursprungstext) wird vermutlich auch nicht mehr lange auf sich warten lassen.

Sicherheit verbessern: Algorithmus
Der erste Schritt zu einer verbesserten Sicherheit ist es also, einen sichereren Algorithmus zu verwenden. Dabei gilt aber, dass es den einen Algorithmus nicht geben kann, da immer wieder neue Angriffsmöglichkeiten für bestimmte Algorithmen gefunden werden (Bsp.: vor 15 Jahren galt md5 als sicher). Eine vorsichtige Empfehlung vom mir geht Richtung whirlpool und ripemd-160.
In PHP lassen sich diese Algorithmen wie folgt verwenden:
PHP-Code:
$y hash('whirlpool'$_POST['password']); 
Die Funktion hash_algos liefert alle auf der aktuellen Plattform unterstützen Algorithmen. Die hash Funktion ist erst ab PHP 5.1.2 verfügbar.

Wörterbuch-Angriffe
Leider ist aber auch das nicht gut genug, um Passwörter zu schützen. Viele Nutzer verwenden sehr einfache Passwörter, teilweise sogar richtige Worte (prominentes Beispiel aus dem Twitter-Hack: "happiness"), da bietet es sich an, eine Woche lang ein paar der bekanntesten Passwörter zu übersetzen und in einem Index hash -> plain text (in den vorherigen Begriffen: Y -> X) zu speichern.
Dadurch kommt ein Angreifer mit etwas Pech auch sehr schnell an Passwörter ran.

Sicherheit verbessern: Salting
Um vor solchen Gefahren besser geschützt zu sein, sollte man die Passwörter "salzen". Beim Salting wird dem Passwort ein anderer String angehängt. Die einfachste Form des Saltings hängt jedem Passwort den gleichen Salt an:
PHP-Code:
$y hash('whirlpool''foobar' $_POST['password']); 
Diese Form des Saltings (ich nenne das der Einfachheit halber "Global Salting") hat zur Folge, dass ein Angreifer für jede gehackte Seite ein eigenes Wörterbuch anfertigen muss. Das erhöht den Aufwand des Angriffs schonmal deutlich, deshalb ist das die minimalste Form des Saltings, die auf jeden Fall verwendet werden sollte.

Noch besser ist es aber, für jeden Benutzer einen eigenen Salt zu haben (zzgl. zum Global Salting). Das kann entweder eine zufällige Zeichenkette sein, oder sogar der Benutzername. Mir gefällt ein zufälliger, nicht anderweitig mit dem Nutzer verknüpfter Salt am besten, daher werden wir nur den einmal betrachten.

Die Grundidee ist es, zusätzlich zum globalen Salt noch einen zufälligen Salt zum Passwort hinzuzufügen. In etwa so:
PHP-Code:
$y hash('whirlpool''foobar' $_POST['password'] . $uniquesalt); 
Dabei muss man natürlich irgendwoher $uniquesalt holen/erzeugen. Mir gefällt es am besten, diesen Salt direkt in die Passwort-Spalte zu schreiben, also dem Passwort vor- oder nachzustellen. Das macht das ganze für den Angreifer nochmal schwieriger, weil er Salt und Passwort unterscheiden muss.
Damit das möglich ist muss es allerdings eine Regel für den Salt geben: Er muss genau N Zeichen lang sein. Ein Beispiel, wie man das in PHP implementieren könnte, ist folgende Funktion:
PHP-Code:
function generateUniqueSalt() {
    
$saltLength 7;
    return 
substr(uniqid(rand(), true), 0$saltLength);

Praktisches Beispiel
PHP-Code:
<?php
define
('SALT_LENGTH'7);
define('SITE_SALT''foobar');

// LOGIN
    // hole das Passwort aus der Datenbank (Suche nur nach username)
    
$result mysql_query('SELECT password FROM users WHERE username=' mysql_real_escape_string($_POST['username']));
    
$result mysql_fetch_assoc($result);
    
$saltedPassword $result['password'];
    
    
// spalte passwort nach salt und hash des Passworts
    
$salt substr($saltedPassword0SALT_LENGTH);
    
$hash substr($saltedPasswordSALT_LENGTH);
    
    
// hashe aktuelles Passwort plus salts
    
$pass hash('whirlpool'SITE_SALT $_POST['password'] . $salt);
    
    if(
$pass == $hash) {
        
// Login erfolgreich
    
}
    
// REGISTRIERUNG
    
$salt generate_unique_salt(); // Funktion von vorher
    
$pass $salt hash('whirlpool'SITE_SALT $_POST['password'] . $salt);
    
mysql_query(sprintf('INSERT INTO users (username, password) VALUES ("%s", "%s")'
        
mysql_real_escape_string($_POST['username']), $pass));
Zusammenfassung
Beim Speichern von Passwörtern sollte man einen möglichst starken Algorithmus wählen und das Passwort vor dem hashing mit zwei salts erweitern. Einem der für alle Passwörter der Datenbank gleich ist und einem für jedes Passwort individuellem. Dadurch ist es für einen Angreifer, der in den Besitz der Passwörter gelangt, extrem aufwendig, an die Passwörter der Nutzer heranzukommen.

Allerdings sollte man im Kopf behalten, dass dadurch nur die Passwörter selbst sicher gespeichert sind. Der Login an sich ist immer noch angreifbar und erfordert weitere Sicherungen.

Nützliche Links

Geändert von pago (23.04.2009 um 20:38 Uhr)
pago ist offline  
Add Post to del.icio.usBookmark Post in TechnoratiDiesen Beitrag zu Mister Wong hinzufügen!
Thema geschlossen

Lesezeichen


Aktive Benutzer in diesem Thema: 1 (Registrierte Benutzer: 0, Gäste: 1)
 
Themen-Optionen Thema durchsuchen
Thema durchsuchen:

Erweiterte Suche

Forumregeln
Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus


Ähnliche Themen
Thema Autor Forum Antworten Letzter Beitrag
[PHP] Zufallspasswort - Generator Jann Hendrik Tutorials 1 23.11.2007 12:27
[Anmeldeseite]Firefox will Passwort speichern WarrenFaith HTML, XML und CSS 13 10.09.2007 11:54
DAtensatz in Variable Speichern und in eine Tabbele speichern kampfgnom Datenbanken 11 10.12.2006 20:45
Sicherheit der Passworteingabe und md5() WarrenFaith PHP-Programmierung 79 24.08.2006 18:39


Alle Zeitangaben in WEZ +1. Es ist jetzt 18:11 Uhr.


Powered by vBulletin® Version 3.8.4 (Deutsch)
Copyright ©2000 - 2010, Jelsoft Enterprises Ltd.
Search Engine Optimization by vBSEO 3.3.0

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47