Heru: pregmatch -> undenliche Prüfung von Variablen (SONDERZEICHEN)

Hallo,

ich möchte gerne meine per GET übertragenen Variablen auf richtigkeit Prüfen. Neben dem Abgleich mit den in der Datenbank eingetragenen Daten möchte ich vorher die typischen XSS Inhalte abfangen.

Hierfür habe ich mir Pregmatch ausgesucht. Mein erster Ansatz sieht auch schon ganz gut aus:

$check = $_GET['test1'] . $_GET['test2'] . $_POST['test3'];  
if (false === preg_match ('#[A-Z].*[a-z].*[0-9]#', $check)) {  
  // error  
}

Nun ist mir beim testen aufgefallen, das ich noch ein leerzeichen, bindestrich als auch die deutschen Sonderzeichen ß,ö,ä,ü,Ö,Ä,Ü nicht dabei berücksichtigt habe.
Wie kann ich die hier einfügen?

Danke Heru

  1. Wie kann ich die hier einfügen?

    Howdy

    Lieber gar nicht. Lösche diese byzantinische Anweisung.

    Du solltest eher htmlspecialchars() anwenden, wenn und nur wenn du im HTML Kontext ausgibst.
    Was du aber in deiner DB speicherst sollte (ich rate mal) mysql_real_escape_string() heissen.
    Mehr dazu unter...
    http://aktuell.de.selfhtml.org/artikel/php/kontextwechsel/

    mfg Beat

    --
    ><o(((°>           ><o(((°>
       <°)))o><                     ><o(((°>o
    Der Valigator leibt diese Fische
    1. Hallo Beat,

      leider ist htmlspeacialchars() nicht das Ende aller dinge gerade UTF7 ist hier besonders hilfsbreit. http://shiflett.org/blog/2007/may/character-encoding-and-xss

      Daher mache ich Pregmatch UND htmlspecialchars() aber dafür muss ich die anderen sachen ÄÖÜöäü ß leerzeichen und - halt erst orgendlich prüfen...

      Danke

      Heru

      1. Ich kann mir jetzt ein WTF nicht ganz verkneifen.

      2. leider ist htmlspeacialchars() nicht das Ende aller dinge gerade UTF7 ist hier besonders hilfsbreit. http://shiflett.org/blog/2007/may/character-encoding-and-xss

        Also damit im MSIE überhaupt UTF7 angewendet wird, muss schon einiges zusammenkommen. Sobald du selber eine von UTF-7 verschiedenes Encoding im HTTP Header oder meta angibst, ist da eigentlich keine Chance.

        Das sagt auch deine verlinkte Seite:
        "When using htmlspecialchars() without specifying the character encoding, XSS attacks that use UTF-7 are possible."

        Also definiere das Character-Encoding und gut ist es.

        mfg Beat

        --
        ><o(((°>           ><o(((°>
           <°)))o><                     ><o(((°>o
        Der Valigator leibt diese Fische
        1. Hallo Beat,

          ich habe es gerade probiert:
          header('Content-type: text/html; charset=utf-8');
          und
          <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />

          dann übergebe ich
          <a+href%3D"http%3A%2F%2Fgoogle.de"><h1+style%3D"color%3Ared">Zu+Google<%2Fh1><%2Fa>

          und trotzdem funktioniert es ....

          1. Hi!

            dann übergebe ich
            <a+href%3D"http%3A%2F%2Fgoogle.de"><h1+style%3D"color%3Ared">Zu+Google<%2Fh1><%2Fa>
            und trotzdem funktioniert es ....

            "Funktioniert" oder "funktioniert nicht" funktioniert nicht. Beobachte und beschreiben bitte genauer, was ist, was sein soll und/oder was nicht sein soll.

            Wenn es dir nur darum geht, dass das obige Gebilde nicht als Code in deiner Seite landet, dann gib ihn nicht als Code aus sondern als Daten mit entsprechender Behandlung der Zeichen mit besonderer Bedeutung.

            Lo!

            1. Wenn es dir nur darum geht, dass das obige Gebilde nicht als Code in deiner Seite landet, dann gib ihn nicht als Code aus sondern als Daten mit entsprechender Behandlung der Zeichen mit besonderer Bedeutung.

              Wofür htmlspecialchars() idr. völlig ausreicht - unabhängig von der Zeichencodierung.

  2. Hi,

    Hierfür habe ich mir Pregmatch ausgesucht. Mein erster Ansatz sieht auch schon ganz gut aus:
    if (false === preg_match ('#[A-Z].*[a-z].*[0-9]#', $check)) {

    Wirklich?
    Das testet auf

    • beliebige Zeichen (da keine Verankerung am Stringanfang)
    • gefolgt von einem Großbuchstaben
    • gefolgt von beliebigen Zeichen
    • gefolgt von einem Kleinbuchstaben
    • gefolgt von beliebigen Zeichen
    • gefolgt von einer Ziffer
    • gefolgt von beliebigen Zeichen (da keine Verankerung am Stringende)

    <A-!"§$%a@€\°0>

    wird also gematcht.

    Nun ist mir beim testen aufgefallen, das ich noch ein leerzeichen, bindestrich als auch die deutschen Sonderzeichen ß,ö,ä,ü,Ö,Ä,Ü nicht dabei berücksichtigt habe.
    Wie kann ich die hier einfügen?

    Umlaute und Leerzeichen sind weder inner- noch außerhalb von Zeichenklassen mit Sonderbedeutung belegt (solange der x-Modifier nicht benutzt wird, dann ist whitespace, also das Leerzeichen, spezialzubehandeln), also einfach reinschreiben.
    Der Bindestrich ist außerhalb der Zeichenklasse ohne Sonderbedeutung, kann also dort auch einfach so notiert werden. Innerhalb der Zeichenklasse muß er als letztes Zeichen notiert werden (oder als erstes bzw. falls das erste Zeichen der Negierungsoperator ^ ist als 2. Zeichen), um ihn seiner Sonderbedeutung zu berauben.

    Aber ich glaube nicht, daß Dein Ausdruck durch Hinzufügen dieser Zeichen besser wird.
    Denn vermutlich willst Du etwas komplett anderes abprüfen als das, was Dein momentaner Ausdruck prüft ...

    cu,
    Andreas

    --
    Warum nennt sich Andreas hier MudGuard?
    O o ostern ...
    Fachfragen per Mail sind frech, werden ignoriert. Das Forum existiert.
    1. Hallo Andreas,

      wäre dann preg_match("/[1]+$/", $check) besser?


      1. a-zA-Z0-9 ↩︎

      1. wäre dann preg_match("/[1]+$/", $check) besser?

        Wofür besser?


        1. a-zA-Z0-9 ↩︎

      2. Hallo,

        oder

        preg_match("/[1]+$/", $check) besser?

        Gruß

        jobo


        1. a-zA-Z0-9äöüetcpp ↩︎

  3. Guten Tag! Opa Horst hat eine Änderung beim Transfer über $_POST entdeckt.
    Also hatte ich bislang deutschen Sonderzeichen ß,ö,ä,ü,Ö,Ä,Ü per Post senden lassen und wie folgt umgewandelt:
    $neuze =  Array('Ae','Oe;','Ue','ae','oe','ue','ss','_');
    $ander =  Array(chr(196),chr(214),chr(220),chr(228),chr(246),chr(252),chr(223),' ');

    $help  =  str_replace($ander,$neuze,$_POST[feld]);
    Also ASCII -analoge Zeichen eingesetzt.

    Das lief bisher gut - bis - es nicht mehr lief!
     Es kam nicht mehr Ä = chr(196) an, sondern deren Umwandlung in UTF-8 Code!!!

    Wenn es dem Einen oder Anderen etwas holprig vorkommt, meine Art Befehle zu schreiben, werde ich trotzdem hier meine Routine zur Umwandlung von UTF-8 Code in Dezimalcode veröffentlichen.
    Die maximalen 7 Byte werden hier nicht berücksichtigt - nur 4 Byte,
    was , so glaube ich den üblichen Codeumfang umfasst.

    <?php // Ausgabe der UTF-8 Daten
    function utf8_out1($str)  // Beim UTF 8 -Code wird Jedes Zeichen durch 1,2,3 oder theoretisch

    {   // bis zu 7 Byte beschrieben
      $k = strlen($str);   // im Startbyte ist die Anzahl der gesetzten führenden Bits
      $i = 0;

    $erg = '';     // gleich der Anzahl der benutzten Bytes, es folgt ein 0-Bit

    while ($k >= $i)     // in jedem Folgebyte ist das erste Bit gesezt, es folgt ein 0-Bit
        {             // aus den anderen Bits ist der Zeichencode zu erstellen
    $dec = ord($str[$i]);    // LESE DAS ERSTE BYTE

    $bytes = $dec >> 4;			// Überprüfe die ersten 4 führenden Bits   		  
    

    // Erweiterter Code Latin 1 direkt übernehmen

    if(($i==$k-1)|| (ord($str[$i+1])>>7)==0)  
    	     {$erg=$erg. chr($dec);$i ++ ;}  
    elseif (($bytes < 8))  
    	     {$erg=$erg. chr($dec);			// kein Führendes Bit gesetzt =  ASCII - Code  
    

    $i ++ ;}
    else   // Diese Routine funktioniert nur mit UTF 8 Code,
      {   // der Zeichen mit maximal 4 Byte beschreibt
    switch($bytes)
                   {
                      case 15:
                         $bytes = 4;// $bytes = Anzahl der Byte, die den Zeichencode enthalten
         $mask = 7;// $mask  = Maske zum löschen der Steuerbits
                         break 1;
                      case 14:
                         $bytes = 3;
         $mask = 15;
                         break 1;
                      case 13:
                         $bytes = 2;
         $mask = 63;
                         break 1;
                      case 12:
                         $bytes = 2;
         $mask = 63;

    }
    $out = 0;
    $shift= 6; // $shift = verschieben zum Zusammensetzen
    if( $i+$bytes > $k) // doch ein Zeichen aus ANSI-Code
      {$erg = $erg.chr($dec);$i ++;}
    else
      {
       for ($l = 0; $bytes-1; $l++)
        {if($l>=$bytes) break 1;// falls (weil!) die Schleife nicht anders beendet wird
         $dec =(ord($str[$l+$i])& $mask);// Lösche Beschreibungsbits

    	     if ($l >0){$out =$out<<$shift;}  
    			// Verschieben der bereits gelesenen Bits  
    

    $out+=$dec;// Summiere Ergebniscode
           $mask = 63;
    }
    $erg=$erg. "&#".$out.";";
    $i = $i + $bytes;
    }
        }
     }

    return rtrim($erg);
    }
    ?>
     Na-Ja Bitmanipulation ist vielleich nicht Jedermanns Sache!
    Die anschliessende Bearbeitung erfolgt so:

    $neuze =  Array('Ae','Oe;','Ue','ae','oe','ue','ss','_');
    $ander =  Array("&#196;","&#214;","&#220;","&#228;","&#246;","&#252;","&#223;"," ");
    $oder  =  Array(chr(196),chr(214),chr(220),chr(228),chr(246),chr(252),chr(223),' ');
    $name=utf8_out1($name);
    $dname=str_replace($ander,$neuze,$name);
    $dname=str_replace($oder,$neuze,$dname);

    Hoffentlich klappt's Opa Horst

    1. Tsaangu beaichehku!

      Also hatte ich bislang deutschen Sonderzeichen ß,ö,ä,ü,Ö,Ä,Ü per Post senden lassen und wie folgt umgewandelt:
      $neuze =  Array('Ae','Oe;','Ue','ae','oe','ue','ss','_');
      $ander =  Array(chr(196),chr(214),chr(220),chr(228),chr(246),chr(252),chr(223),' ');

      Ohne jetzt die Effizienz Deines Codes untersucht zu haben halte ich von solchen Ersetzungen offen gestanden wenig bis gar nichts. Weiß und Weiss sind per definitionem zwei unterschiedliche Namen, also geht hier Information verloren.
      Bei der Ausgabe sieht es IMHO auch ziemlich holprig aus, wenn diese Fallbacks wie ue im Text stehen, und automatische Rück-Ersetzung geht nicht – dafür ist das stur ersetzende Script einfach nicht intellektüll genug.
      Zudem ist so eine Liste nie vollständig; auch in Deutschland muß man mit René, André oder Stanisław rechnen. Eventuelle typographisch korrekte Satzzeichen (–’„“…) fehlen auch, und ja, die können auch von unbedarften Anwendern kommen (wenn die z.B. ihren Text in Word tippen, dieses Zeichen wie " und ' automatisch ersetzt, und die User den Text dann in das Eingabefeld kopieren).

      Besser ist es, alle Zeichen so zu lassen, wie sie sind, das verarbeitende Script so zu bauen, daß es damit klarkommt, und überall eine einheitliche Kodierung zu verwenden (für westeuropäische Projekte ist nur UTF-8 sinnvoll). Bei Aus- oder Weitergabe der Daten muß ggf. kontextgerecht escaped werden, z.B. in URLs.

      Falls es um Dateinamen geht: Die würde ich grundsätzlich selbst setzen und nicht dem User überlassen. Dateinamen mit Sonderzeichen können, wenn nicht schon auf dem Server, immer bei irgendwelchen Clients Probleme machen.

      Viele Grüße vom Længlich

      --
      Mein aktueller Gruß ist:
      Shoshoni (USA)