MH: Passwort Generator

Moin,
ich hab mir eine Passwort Generator gebastelt.
Es wir ein Passwort generiert, dies hat 10 Zeichen. Das Passwort wird mit einem Array abgeglichen, in dem alle bisher generierten Passwörter stehen. Solange es in dem Array steht wir es neu generiert, ansonsten wird es im Array gespeichert und das Passwort wird in einer DB gespeichert.
Nun ist mir aber aufgefallen, dass die Passwörter, die ja eigentlich immer 10 Zeichen haben sollen, zum Teil weniger bis gar keine Zeichen haben. Ich hab jetzt schon einiges versucht, es aber nicht hinbekommen das zu beheben.
Hat jmd. von euch eine Idee woran das liegt?
Hier mein Code:

$psw = array();
for($i = 0; $i < $anz; $i++){
	$pw = '';
  for($a = 0; $a < 10; $a++){
      $pw .= substr('./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghjklmnopqrstuvwxyz0123456789!§$&=?@+*#', mt_rand(0, 73), 1);
  }
  while(in_array($pw, $psw)){
      $pw = '';
      for($b = 0; $b < 10; $b++){
          $pw .= substr('./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghjklmnopqrstuvwxyz0123456789!§$&=?@+*#', mt_rand(0, 73), 1);
      }
  }
  $psw[] = $pw;
	
	$query = sprintf(
  	"INSERT INTO `codes` (`code`, `abt`, `funktion`)
    VALUES ('%s', '%s', '%s')",
    $mysqli->real_escape_string($pw),
    $mysqli->real_escape_string($row['preffix'] . $row['suffix']),
    $mysqli->real_escape_string('Besucher')
  );
  $mysqli->query($query);
}

Danke schon mal
Gruß
MH

  1. Hi,

    $psw = array();
    for($i = 0; $i < $anz; $i++){
    	$pw = '';
      for($a = 0; $a < 10; $a++){
          $pw .= substr('./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghjklmnopqrstuvwxyz0123456789!§$&=?@+*#', mt_rand(0, 73), 1);
      }
      while(in_array($pw, $psw)){
          $pw = '';
          for($b = 0; $b < 10; $b++){
              $pw .= substr('./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghjklmnopqrstuvwxyz0123456789!§$&=?@+*#', mt_rand(0, 73), 1);
          }
      }
      $psw[] = $pw;
    	
    	$query = sprintf(
      	"INSERT INTO `codes` (`code`, `abt`, `funktion`)
        VALUES ('%s', '%s', '%s')",
        $mysqli->real_escape_string($pw),
        $mysqli->real_escape_string($row['preffix'] . $row['suffix']),
        $mysqli->real_escape_string('Besucher')
      );
      $mysqli->query($query);
    }
    

    Da ist ziemlich viel wiederholter Code drin, das solltest Du ändern.

    Ich würde den String der erlaubten Zeichen als Variable oder Konstante festlegen, und dann nicht die hartcodierte Länge bei rand angeben, sondern dazu strlen auf die Konstante anwenden (und natürlich 1 abziehen, da bei 73 Zeichen diese Indizes von 0 bis 72 haben).

    Wenn Du beim jetzigen Code ein neues Zeichen erlaubst oder ein bestehendes nicht mehr erlauben willst, mußt Du statt an einer Stelle an vier Stellen korrigieren.

    Die 73 dürfte auch das Problem sein - da nur Positionen von 0 bis 72 vorhanden sind, gibt substr dann vermutlich einen Leerstring zurück (müßte man im Handbuch nachgucken).

    Warum dürfen eigentlich nicht 2 User das selbe Paßwort besitzen? Gibt's dafür einen echten Grund?

    Da $psw am Anfang als leeres Array initialisiert wird, ist nach dem ersten Paßwort-Erzeugen dieses niemals schon im Array, die while-Schleife wird also nie durchlaufen. Es findet also eh keine Duplikats-Prüfung statt - dazu müßte am Anfang $psw mit allen vorhandenen Paßwörtern gefüllt werden.

    Und selbst dann wäre kein Duplikatsschutz gegeben, denn wenn zwei User das Paßwort-generieren zufällig gleichzeitig auslösen und zufällig auch das gleiche Paßwort bekommen, wäre es bei beiden noch nicht in $psw …

    cu,
    Andreas a/k/a MudGuard

    1. Moin,

      Warum dürfen eigentlich nicht 2 User das selbe Paßwort besitzen? Gibt's dafür einen echten Grund?

      Hierbei handelt es sich nicht um Passwörter für User eines Portals oder so, sondern um Passwörter, um ein Formular auszufüllen. Da das Passwort noch für eine abgleich verwendet wird darf es nicht vorkommen, dass das Passwort einer Abteilung (abt) in einer anderen nochmal existiert.

      Die 73 dürfte auch das Problem sein - da nur Positionen von 0 bis 72 vorhanden sind, gibt substr dann vermutlich einen Leerstring zurück (müßte man im Handbuch nachgucken).

      Ja, die 73 war ein Fehler, hab das jetzt mit der strlen($chars) überbrückt. Der Hauptfehler war jedoch, wie andaris geschrieben hatte, das Paragraphen Symbol.

      Es kommt jetzt zwar nicht mehr dazu, dass es Leerstrings oder mit nur einem Zeichen gibt, aber manchmal gibt es noch welche wo nur 9 Zeichen sind. Auf dieses 1 Zeichen kommt es mir jetzt nicht an, aber wenn doch noch jmd. oder du ne Idee hat woran das noch liegen könnte wäre das toll.

      Gruß
      MH

    2. Warum dürfen eigentlich nicht 2 User das selbe Paßwort besitzen?

      Ist das nicht sogar potentiell gefährlich? Ich muss "nur" ein mal alle Passwörter bruteforcen und weiss dann welche in der Datenbank stehen. Und nur die muss ich dann noch für jeden User ausprobieren.

      1. Hallo chorn,

        da die PW rein zufällig sind, sind es nur $${72}^{10} \approx 3.7 \cdot {10}^{18}$$ Stück, das wird durch kein Wörterbuch reduziert.

        Damit bist Du recht zügig durch.

        Rolf

        --
        Dosen sind silbern
        1. Hello,

          da die PW rein zufällig sind, sind es nur $${72}^{10} \approx 3.7 \cdot {10}^{18}$$ Stück, das wird durch kein Wörterbuch reduziert.

          außerdem könnte die Datenbank auch Honigpötte enthalten. Ich würde es so machen, auch wenn ich selbstverständlich niemals die PW im Klartext speichern würde.

          Und Hashes könnten ohnehin doppelt auftreten, auch wenn die PW nicht doppelt sind. Aber auch diese Wahrscheinlichkeit ist sehr gering.

          Liebe Grüße
          Tom S.

          --
          Es gibt nichts Gutes, außer man tut es
          Andersdenkende waren noch nie beliebt, aber meistens diejenigen, die die Freiheit vorangebracht haben.
  2. Hi MH!

    Du erzeugst bei der Zufallszahl möglicherweise einen Out-of-Bounds Error. Dein String mit zulässigen Zeichen ist 73 Zeichen lang, somit hat das letzte den Index 72 (das erste Zeichen hat Index 0). Ändere dein mt_rand() also mal auf mt_rand(0, 72).

    Übrigens solltest du das Paragraphsymbol entfernen, da es nicht Teil des ASCII-Standards (Codepoints 0-127) ist. Somit würde sich der Bereich auf (0,71) ändern, da dann 72 Zeichen übrig sind.

    LG andaris

    1. Moin,
      Das mit dem Paragraphsymbol war der Hauptfehler. Danke!

      Gruß
      MH

    2. Hello,

      Übrigens solltest du das Paragraphsymbol entfernen, da es nicht Teil des ASCII-Standards (Codepoints 0-127) ist. Somit würde sich der Bereich auf (0,71) ändern, da dann 72 Zeichen übrig sind.

      Auf meinem Tablet-Standard-Zeicheneingabedisplay ist es auch nicht enthalten, auf keiner Ebene. Ich ärgere mich jedes Mal, wenn ich es brauche!

      Liebe Grüße
      Tom S.

      --
      Es gibt nichts Gutes, außer man tut es
      Andersdenkende waren noch nie beliebt, aber meistens diejenigen, die die Freiheit vorangebracht haben.
      1. Tach!

        Auf meinem Tablet-Standard-Zeicheneingabedisplay ist es auch nicht enthalten, auf keiner Ebene. Ich ärgere mich jedes Mal, wenn ich es brauche!

        Vielleicht versteckt es sich zusammen mit dem ß hinterm s.

        dedlfix.

  3. Moin MH,

    noch zwei Dinge:

    • Anstelle die Stringlänge der erlaubten Zeichen hartcodiert im Skript zu haben, scheint es mir sinnvoller, das – genau wie diesen String – an zentraler Stelle einmal zu definieren:
    define('PW_CHARS', './ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghjklmnopqrstuvwxyz0123456789!§$&=?@+*#');
    define('PW_CHARL', strlen(PW_CHARS));
    
    • Dein SQL-Query wird in der Schleife ggf. mehrmals ausgeführt. Anstelle den jedes Mal neu zusammen zu bauen und an den Server zu schicken, kannst du ihn einmal vorbereiten und dann mehrmals mit den jeweiligen Daten ausführen.

    Viele Grüße
    Robert

    1. Hallo Robert, @MH

      • Anstelle die Stringlänge der erlaubten Zeichen hartcodiert im Skript zu haben, scheint es mir sinnvoller, das – genau wie diesen String – an zentraler Stelle einmal zu definieren:
      define('PW_CHARS', './ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghjklmnopqrstuvwxyz0123456789!§$&=?@+*#');
      define('PW_CHARL', strlen(PW_CHARS));
      

      Alternativ könnte man ab PHP 7 auch mit einem Array arbeiten, das würde auch das problemlose Handling von Zeichen außerhalb von ASCII erlauben (sofern man sie denn braucht):

      define('PW_CHARS', [',', '.', '/', 'A', 'B', 'C', '§', '…']); // [] ist Kurzform von array() 
      define('PW_CHARL', count(PW_CHARS));
      

      Gruß
      Julius