Passende RegEx für Passwörter

Einklappen
X
 
  • Filter
  • Zeit
  • Anzeigen
Alles löschen
neue Beiträge

  • Passende RegEx für Passwörter

    Hallo,

    ich bin schon ein wenig länger auf der Suche nach einem passenden RegEx für preg_match() unter PHP, der einen übergebenen String darauf hin überprüft, ob Zahlen und Buchstaben enthalten sind.

    Es geht hierbei um ein via Formular übergebenes Passwort. Dieses darf alles mögliche enthalten, es müssen aber mindestens drei Zahlen und drei Buchstaben enthalten sein:

    '123456' >> FALSE
    '12abc' >> FALSE
    '123ab' >> FALSE
    '123abc' >> TRUE
    '123abc#@' >> TRUE
    '12345432bbewoi' >> TRUE
    '278687lkhgaljh##**+?' >> TRUE

    Wer hätte einen guten Ansatz für mich?
    MFG
    salim_aliya
    Lesen, lernen, ausüben und Ziele erreichen...

  • #2
    Das ist so ungefähr Regex Schwierigkeitsgrad 2. Hast du dich überhaupt in das Thema eingelesen? Welche Ausdrücke hast du schon probiert?
    This is what happens when an unstoppable force meets an immovable object.

    Kommentar


    • #3
      Zitat von salim_aliya Beitrag anzeigen
      '123456' >> FALSE
      '12abc' >> FALSE
      '123ab' >> FALSE
      '123abc' >> TRUE
      '123abc#@' >> TRUE
      '12345432bbewoi' >> TRUE
      '278687lkhgaljh##**+?' >> TRUE
      Falls die Reihenfolge immer eingehalten wird, so ist es relativ einfach, da Du dann mit \d{3,} oder mit [0-9]{3,}für 3 oder mehr Ziffern beginnen könntest, gefolgt von zwei weiteren Zeichenklassen und den Angaben für {min,max}, wobei die maximale Anzahl hinter dem Komma weggelassen werden kann. Sollte bezogen auf Deine jetzigen Beispiele wie gewünscht false und true ergeben.
      Code:
      "/\d{3,}[a-zA-Z]{3,}[#@*+?]{0,}/"
      Wenn die Reihenfolge nicht eingehalten wird, wird es etwas komplizierter. So würde das Muster zum Beispiel bei $abc = "12ab34cd"; false ergeben.

      Kommentar


      • #4
        Zitat von Melewo Beitrag anzeigen
        ... Wenn die Reihenfolge nicht eingehalten wird, wird es etwas komplizierter. ...
        Zitat von ApoY2k Beitrag anzeigen
        Das ist so ungefähr Regex Schwierigkeitsgrad 2. ...
        So ganz trivial wird die Lösung am Ende doch nicht, wenn man das Problem unbedingt mit EINEM Regex erschlagen will:

        * Mehrere "Zeichengruppen" sollen UND-verknüpft werden. Dazu benötigt man Assertions, ohne gibt es nur ODER-Verknüpfungen (über alternative Sub-Pattern).

        * Zwischen den gewünschten Zeichen sind beliebige andere Zeichen erlaubt. Die gewünschten Zeichen einer Gruppe können sich daher mit den gewünschten Zeichen einer anderen Gruppe überschneiden. Jeder Suchvorgang muss also erneut am Stringanfang verankert werden (Bsp.:
        'a1b2c3').

        Ein PCRE für den konkreten Fall (mindestens 3 Buchstaben [a-zA-Z] und mindestens drei Ziffern [0-9]) könnte so aussehen:

        PHP-Code:
        $pcre '/
            (?=\A.*(?:[a-zA-Z][^a-zA-Z]*){3}) # 3 letters (ASCII)
            (?=\A.*(?:[0-9][^0-9]*){3})       # 3 digits (ASCII)
        /xs'

        Allerdings sind das keine besonders brauchbaren Anforderungen für ein gutes Passwort. So werden neben Groß-, Klein-Buchstaben und Ziffern auch "Sonderzeichen" gefordert.

        Man könnte jetzt den RegEx per Copy-n-Paste erweitern um bspw. '(?=\A.*(?:[,._#+*?!][^,._#+*?!]*){2})', aber das ist fehleranfällig und macht keinen Spaß. Also automatisieren wir uns das:

        PHP-Code:
        // check if a list of given character classes ("cc") exists in a string
        // POSIX classes and Unicode character properties are allowed
        class ccchecker {

            
        /// constructor
            /// throw InvalidArgumentException
            
        function __construct(
                
        $rules  /// assoc( str(pcre-character-class) => int(1...) );
            
        ) {
                if (!
        is_array($rules)) {
                    throw new 
        InvalidArgumentException('ruleset must be an ARRAY');
                }
                if (empty (
        $rules)) {
                    throw new 
        InvalidArgumentException('empty ruleset');
                }
                
        // build regex
                
        $this->pcre '/';
                foreach (
        $rules as $charclass => $min) {
                    if (!
        is_int($min)) {
                        throw new 
        InvalidArgumentException('$min must be an INTEGER');
                    }
                    if (
        $min || $min 65535) { // 65535 is the builtin PCRE limit
                        
        throw new InvalidArgumentException(
                            
        '$min must be in range 0...65_535'
                        
        );
                    }
                    
        // escape possible closing brackets
                    
        $charclass preg_replace('/(?<!:)]/''\\]'$charclass);
                    if (
                        !
        is_string($charclass) ||
                        !
        is_int(@preg_match(sprintf('/[%s]*/u'$charclass), ''))
                    ) {
                        throw new 
        InvalidArgumentException(
                            
        'given string is not a valid character class in PCRE'
                        
        );
                    }
                    
        $this->pcre .= sprintf(
                        
        '(?=\A.*(?:[%s][^%s]*){%d})'$charclass$charclass$min
                    
        );
                }
                
        $this->pcre .= '/su';
                return;
            }

            
        /// get pcre string
            
        function pcre() {
                return 
        $this->pcre;
            }

            
        /// check if given $str for complies to the defined rules
            
        function check($str) {
                return 
        === preg_match($this->pcre$str);
            }


        Angewendet sieht das dann gar nicht mehr so schlimm aus:

        PHP-Code:
        $rules = array (
            
        // >= 3 letters
            
        'a-zA-Z' => 3// ASCII
            // '[:alpha:]' => 3, // POSIX classes work
            // '\pL' => 3, // Unicode character props work, too

            // >= 3 digits
            
        '0-9' => 3,
        );


        $tests = array (
            
        // invalid
            
        '123456',
            
        '12abc',
            
        '123ab',
            
        // valid
            
        '12ab34cd',
            
        '123abc',
            
        '123abc#@',
            
        '12345432bbewoi',
            
        '278687lkhgaljh##**+?',
            
        'a1b2c3',
        );

        $ccc = new ccchecker($rules);

        foreach (
        $tests as $test) {
            
        $valid $ccc->check($test);
            
        printf("\n<br />valid: %d for %s"$valid$test);

        Klingon function calls do not have “parameters”‒they have “arguments”‒and they always win them!

        Kommentar


        • #5
          Dein Lösungsweg sieht zumindest richtig interessant aus, muss ich mir mal in Ruhe betrachten. Ganz verstehe ich es zumindest nicht, müsste mich erst einmal richtig darin vertiefen. Nur hätte ich es mir etwas einfacher gemacht, sieht aber nicht so gut aus:
          PHP-Code:
          function Pruefe($abc) {

              
          preg_match_all("/\d/"$abc$was);
              
          preg_match_all("/[a-zA-Z]/"$abc$wie);

              
          $wasc count($was[0]);
              
          $wiec count($wie[0]);

              if (
          $wasc 2) {

                  if (
          $wiec 2) {echo "Es sind mindestens 3 Ziffern und 3 Buchstaben enthalten.\n";
                  }
                  else {echo 
          "Es sind nur ".$wiec." Buchstaben enthalten.\n";
                  }
              }
              else {echo 
          "Es sind nur ".$wasc." Ziffern enthalten.\n";
              }
          }

          $passwort "12a#c#b3**4c5d+?d";

          Pruefe($passwort); 
          Und mit einer Prüfung auf unerlaubte Zeichen sind es noch drei Zeilen mehr:
          PHP-Code:
          function Pruefe($abc) {

              
          preg_match("/[^a-zA-Z0-9#@*+?.,:_]/"$abc$wau);
              
          preg_match_all("/\d/"$abc$was);
              
          preg_match_all("/[a-zA-Z]/"$abc$wie);
              
              
          $wauc count($wau);
              
          $wasc count($was[0]);
              
          $wiec count($wie[0]);

              if (
          $wauc == 0) {
              
                  if (
          $wasc 2) {

                      if (
          $wiec 2) {return "Es sind mindestens 3 Ziffern und 3 Buchstaben enthalten.\n";
                      }
                      else {return 
          "Es sind nur ".$wiec." Buchstaben enthalten.\n";
                      }
                  }
                  else {return 
          "Es sind nur ".$wasc." Ziffern enthalten.\n";
                  }
              }
              else {return 
          "Es sind unerlaubte Zeichen enthalten!";
              }
          }

          $passwort "12a#c#b3**4c5d+?d";

          echo 
          Pruefe($passwort); 
          Zuletzt geändert von Melewo; 21.01.2013, 08:28.

          Kommentar


          • #6
            Zitat von Melewo Beitrag anzeigen
            ... Nur hätte ich es mir etwas einfacher gemacht, ...
            PHP-Code:
            // ... 
            Ich hatte ja schon geschrieben, dass dieser "Aufwand" nur nötig ist, wenn man das Problem unbedingt mit EINEM EINZIGEN REGEX erschlagen möchte. Man könnte ihn ohne weiteres auftrennen und mehrmals mit
            preg_match('/(?:[0-9][^0-9]*){3}/')
            (usw.) über die Benutzereingaben gehen. Das wäre bei deinem Kenntnis-Stand (keine Assertions?) vielleicht angebrachter.

            Auch ist es möglich, das Ganze diskret in PHP zu realisieren, sprich: Einfach Zeichen verschiedener Art (Ziffern, Buchstaben, e.t.c.) zu zählen. PHP's eingebaute String-Funktionen bekommen hier Probleme, wenn die Benutzereingaben bspw. als UTF-8 hereinkommen. Ich verlasse mich da lieber auf die Fähigkeiten der PCRE-Funktionen.

            Meine Klasse gibt aber nicht ohne Grund mit der Methode ->pcre() den zusammengeklebten Regex her. Den kannst du kopieren und in einem Script ganz einfach mit preg_match() verwenden:

            PHP-Code:
            // riesenlangen Wunsch-Regex hier reinkopieren
            $check_allowed_chars '/.../'

            // ... weiter im Script

            if (!preg_match($check_allowed_chars$benutzereingabe)) {
                
            // Eingabe gefaellt mir nicht
            }
            else {
               
            // in Ordnung 

            Bei deiner diskreten Lösung musst du den Quelltext jedesmal umbauen, wenn sich die Anforderungen ändern. Bei meinem Ansatz fügst du lediglich dem Regelsatz-Array ($rules) einen neuen Eintrag hinzu.

            Es fehlt noch der Ausschluss von unerwünschten Zeichen (bspw. "non-printable"). Das könnte man aber relativ einfach nachrüsten.
            Zuletzt geändert von fireweasel; 21.01.2013, 19:28. Grund: typo
            Klingon function calls do not have “parameters”‒they have “arguments”‒and they always win them!

            Kommentar

            Lädt...
            X