2015-05-09 5 views
10

Die Verwendung von srand(time()) zum Generieren eines Tokens für ein Zurücksetzen des Kennworts (oder für ein CSRF-Token) ist schlecht, da das Token vorhersehbar sein kann.Warum Srand (Zeit()) ist ein schlechter Samen?

Ich lese diese:

Aber ich verstehe nicht, wie das Token vorhersehbar sein kann. Ich verstehe, wenn ich in einer Sekunde mein Passwort viele Male zurücksetze, bekomme ich das gleiche Token. Ich habe den folgenden Code:

<?php 

srand(time()); 
$reset_password_token = rand(444444444444,999999999999); 

?> 

Wenn ich in 1 Sekunde viele Male mein Passwort zurückzusetzen, ich weiß, dass ich das gleiche Token erhalten, aber wie kann das ein Angreifer ausnutzen?

+0

Der Seed ist nur ein Problem. Die Verwendung von "rand" selbst, selbst mit einem unvorhersehbaren Seed, ist eine Sicherheitslücke. –

Antwort

13

Es begrenzt den Umfang ihrer rohen Gewalt. Zum Beispiel müssen sie nur 60 Passwörter versuchen, wenn sie wissen, dass jemand in der letzten Minute einen Reset durchgeführt hat.

Aber es ist schlimmer als das. Der Angreifer kann ein beliebiges Konto aufrufen, indem er eine Kennwortzurücksetzung für dieses Konto einleitet. Danach erzeugen sie ein paar Token, indem sie srand mehrmals mit dem Unix-Zeitstempel für das kleine Zeitfenster um das Reset herum aufrufen und jedes Mal inkrementieren. Einer dieser Tokens muss übereinstimmen, es sei denn, Ihre Uhr ist weit entfernt.

+0

Supose Ich kenne genau den Zeitstempel und kenne den Algorithmusgenerator (Bereichsnummer wie mein Beispiel). Wenn ich verstehe, wenn ich dies versuchen: 'while (1) {// ein neues Token genere und erfassen den Zeitstempel in der Website srand ($ sametimestamp); $ reset_password_token = rand (444444444444,999999999999); // Testen Sie das Token auf der Website Sleep (3); // für den Test erneut mit einem neuen Zeitstempel } ' Ich kann das Token erraten? – sushi

+1

ja. Versuch es. Die Ausgabe von rand (444444444444,999999999999) wird durch den in srand eingegebenen Wert bestimmt. –

+0

Ich versuche das und es funktioniert nicht. Ich denke, vielleicht, wenn ich viele Token mit einem Zeitstempel mit 5 Minuten Vorsprung erzeuge, ist es vielleicht Arbeit? – sushi

7

Zeitrahmen Angriff

Der Angreifer kann wissen/erraten, die Zeit Ihres Systems. Natürlich kann ein Hacker die genaue Sekunde nicht wissen, denn für die meisten Server kann das ein bisschen anders sein.

Aber sagen zum Beispiel Ihre lokale Zeit ist:

> echo time(); 
1431212010 

dann können Sie eine „gute Vermutung“, dass die Samen zwischen 1431212005 und 1431212015 befinden wird.

Also wenn Sie wie 10 Vermutungen machen können, sind die Chancen sehr wahrscheinlich, dass das Passwort korrekt ist.

Natürlich muss der Hacker noch den Algorithmus kennen, der das Passwort "generiert". Aber für die meisten Systeme ist das ziemlich einfach und außerdem wie immer in der Sicherheit, es ist besser, dass man sowieso nicht viel über das System weiß. Schließlich können die meisten Hacker ihren eigenen Account erstellen und "inspizieren", wie das Passwort generiert wird, und zunächst nach Mustern suchen.

Wenn der Hacker ein Konto hat er/sie selbst

Eine wirklich bequeme Art und Weise derjenigediejenigedasjenige Passwörter hacken weiterhin zwei Anfragen zum Zurücksetzen des Passworts im selben Moment etwa post: sagen Sie ein Konto X haben und Sie mögen Konto hacken Y. Innerhalb einer Millisekunde können Sie zwei Anfragen stellen, eine für sich selbst und eine für das Opfer. Als nächstes erhalten Sie Ihr Passwort und Sie können es für beide Konten verwenden. Wie @AlfredRossi sagt, kannst du außerdem über alle Accounts der Website aufzählen und somit die meisten Accounts hacken.

Lösungen

Die meisten Systeme bieten eine Möglichkeit, „echten Zufall“ zu erzeugen (natürlich fraglich ist es, ob wir über echten Zufall sprechen).Zum Beispiel, indem Sie das Rauschen auf den Audiokanälen erfassen oder andere "Geräusche" hören. Diese Werte sind weniger vorhersehbar, da man kaum erraten kann, wie hoch die gemessene Intensität eines Audiokanals einige tausend Meilen von seinem Standort ist.

+1

'Die meisten Systeme bieten eine Möglichkeit," real random "zu generieren (natürlich ist es fraglich, ob wir über echte Zufallszahlen sprechen)' Mehr auf den Punkt, [Sie wollen nicht wirklich zufällig] (http://sockpuppet.org/blog/2014/02/25/safe-generate-random-numbers) für die Kryptographie. –

+0

Würde nicht eine laufende, inkrementierende Ganzzahl, die dem Timeseed hinzugefügt wurde, beiden Angriffen entgegenwirken? – Wortex17

+0

@ Vortex17: Wenn der Hacker ein Konto hat, kann er/sie versuchen, diesen Zähler zu rekonstruieren. Darüber hinaus * counter * ein Angriff ist vielleicht eine schlechte Wortwahl. Sicherheit ist keine On/Off-Story, vielmehr geht es darum, eine Risikominimierung in vernünftigen Grenzen zu setzen. –

13

Gute Lösungen

Dies setzt voraus, ein 256-Bit-nonce erforderlich ist.

  1. random_bytes(32) (PHP 7.0.0+)
  2. openssl_random_pseudo_bytes(32)
  3. mcrypt_create_iv(32, MCRYPT_DEV_URANDOM)
  4. von /dev/urandom Lesen

-Code-Snippet für # 4:

<?php 
function getRandom($bytes) 
{ 
    // Read only, binary safe mode: 
    $fp = fopen('/dev/urandom', 'rb'); 

    // If we cannot open a handle, we should abort the script 
    if ($fp === false) { 
     die("File descriptor exhaustion!"); 
    } 
    // Do not buffer (and waste entropy) 
    stream_set_read_buffer($fp, 0); 

    $entropy = fread($fp, $bytes); 
    fclose($fp); 
    return $entropy; 
} 

Bad Solu

gen
  • mt_rand()
  • rand()
  • uniqid()
  • microtime(true)
  • lcg_Value()

Was eine Lösung gut macht?

Eine gute Lösung sollte einen kryptografisch sicheren Pseudozufallszahlengenerator (CSPRNG) nutzen. Auf Unix-basierten Betriebssystemen kann dies durch direktes Lesen von /dev/urandom erreicht werden.

Aber ich verstehe nicht, wie das Token vorhersehbar sein kann.

Dieses Thema wurde ziemlich ausführlich behandelt.

ich den folgenden Code haben:

<?php 

srand(time()); 
$reset_password_token = rand(444444444444,999999999999); 

?> 

Theoretisch wäre es sei nur 555555555555 mögliche Werte dafür. Leider ist die tatsächliche Nummer viel niedriger.

rand() verwendet einen Algorithmus, der als linearer kongruenter Generator bezeichnet wird, der aufgrund seiner Implementierung in PHP 5 nur mit vorzeichenlosen 32-Bit-Ganzzahlen arbeitet. Beide von Ihnen angegebenen Nummern sind größer als 2**32. Ich bin mir nicht sicher, ob es überlaufen würde. The source code ist in diesem Fall nicht sehr aufschlussreich.

Da Sie jedoch Ihre Zufallszahlen mit time() seeding, werden Sie in Schwierigkeiten geraten. Schnell, führen Sie diesen Code:

<?php 

srand(1431223543); 
echo rand()."\n"; 

Sie sollten 1083759687 in der Konsole sehen. Im Allgemeinen ist der Zeitunterschied zwischen Computern im Internet ziemlich klein. Sie könnten wahrscheinlich nur einen möglichen Jitter von bis zu 2 Sekunden in jeder Zeitzone berücksichtigen, und Sie würden nur 120 Berechnungen (im schlimmsten Fall) benötigen, um mit der Vorhersage der Zufallszahlenausgabe zu beginnen. Für immer.

Bitte verwenden Sie für alles, was die Sicherheit Ihrer Anwendung betrifft, ein CSPRNG.

+0

Anders als '/ dev/urandom' ist'/dev/random' interessant, weil es versucht, hohe Entropie zu garantieren, so dass es Lesevorgänge blockiert, bis genügend Bits im Entropie-Pool verfügbar sind. –

+1

Die Anzahl der Vermutungen kann auch reduziert werden, indem Sie nachsehen, wo sich der Server befindet und somit die Zeitzone "erraten". Wenn man einige berechnete Vermutungen anstellt, wird es wahrscheinlich weniger Vermutungen erfordern. –

+0

@CommuSoft Sie sind natürlich richtig. Realistischerweise können Sie es wahrscheinlich in weniger als 3 Versuchen erraten. Ich bot 120 als Obergrenze an. –

0

Wenn ich mein Passwort viele Male in einer Sekunde zurücksetze, weiß ich, dass ich das gleiche Token bekomme, aber wie ein Angreifer das ausnutzen kann?

Sie haben die Sache, die ein Angreifer "viele von" falsch machen muss. Ein Angreifer kann für viele verschiedene Sekunden eigene Tokens generieren und sie gegen Ihr Konto versuchen.