PHP Sicherheit – Benutzereingaben überprüfen

Von 13. Februar 2012 Web-Entwicklung 9 Kommentare

Die Überpüfung von Benutzereingaben zum Beispiel per GET- und POST-Variablen ist in PHP enorm wichtig. In diesem Artikel möchte ich Sicherheitsmaßnahmen zeigen, die über eine Maskierung von Benutzereingeben hinaus gehen.

Oft wird in PHP die Funktion mysql_real_escape_string genutzt um SQL-Injections bzw. die Ausführung von übergebenen Code zu verhindern.

<!--?php $auswahl = mysql_real_escape_string($_POST['auswahl']); ?-->

Dies reicht meist jedoch nicht aus, um alle Sicherheitslücken zu beheben. Ich zeige an einem Beispiel warum.

Überprüfen der möglichen Werte

Nehmen wir als Beispiel folgendes HTML-Formular welches eine Auswahl von Werten darstellt und ein verstecktes Feld. Diese werden dann per POST übergeben.

</pre>
<form action="" method="post">Auswahl:
<select name="auswahl">
<option value="Auswahl 1">Auswahl 1</option>
<option value="Auswahl 2">Auswahl 2</option>
<option value="Auswahl 3">Auswahl 3</option>
</select>

<input type="hidden" name="versteckt" value="du siehst mich nicht" />
<input type="submit" value="Senden" /></form>
<pre>

Würden wir die Werte per GET übergeben, so könnte man diese einfach in der URL anpassen. Wir übergeben diese aber per POST. Viele denken, dies wäre die sichere Variante. Mit etwas Wissen kann man jedoch auch diese Werte ohne weiteres anpassen. So kann man zum Beispiel die Auswahl um weitere Optionen erweitern oder den Wert des versteckten Feldes beliebig anpassen.

Somit müssen wir immer bei einer Benutzereingabe überprüfen, ob die übergebenen Werte überhaupt möglich sind bzw. zur Auswahl standen oder ob Änderungen vorgenommen wurden.

Die Überprüfung der Auswahl sollte dann so aussehen:

$auswahl = "";
$var1 = mysql_real_escape_string($_POST['auswahl']);
switch($var1)
{
case "Auswahl 1": $auswahl = $var1; break;
case "Auswahl 2": $auswahl = $var1; break;
case "Auswahl 3": $auswahl = $var1; break;
default: $auswahl="";break;
}

Wie Sie sehen, erweitern wir das Script um eine Switch-Anweisung. Diese überprüft, ob sich in $_POST['auswahl'] eines der 3 möglichen Werte befindet. Ist dies so, wir dieser Wert in $auswahl geschrieben. Befindet sich ein Wert darin, welcher nicht möglich ist, so bleibt $auswahl leer. Das selbe können wir mit $_POST['versteckt'] tun.

Über Peter

Ich bin seit 2008 selbständiger Web-Entwickler und Inhaber von Design-Insel.de. Ich versorge meine Kunden mit anspruchsvollen und erfolgsorientierten Weblösungen. Dazu zählen mittelständische aber auch größere Unternehmen wie T-Systems und Zalando.

9 Kommentare

  • Udo sagt:

    Ein sehr einfaches, dennoch sehr effektives Script, danke!

  • admin sagt:

    Kein Problem, in Zukunft wird es noch einiges mehr geben in Hinsicht auf PHP-Sicherheit

  • chris sagt:

    Anstelle des Switch/Case – Konstrukts, würde ich eher ein Whitelisting in Form eines Arrays bevorzugen, das die validen Werte enthält – evtl. auch mit entsprechender Tiefe für die Validierung mehrerer Felder mit unterschiedlichem Namen.

    Dann würde auch ein einfaches in_array() ausreichen und für eine Erweiterung müsste lediglich das Array und nicht die Scriptlogik erweitert werden.

    // Whitelist-Array
    $aMyWhitelist = array(
    ‘auswahl’ => array(‘Auswahl 1′,’Auswahl 2′, ‘Auswahl 3′),
    );

    // Formulardaten durchlaufen und Values gegen Whitelist prüfen
    foreach($_POST as $k => $v){
    if(in_array($v,$aMyWhitelist[$k])){
    $$k = mysql_real_escape_string($v);
    }
    }

    Das Array könnte zentral in einer Config abgelegt werden und bei bedarf sogar so angepasst werden, dass es den Formularnamen oder einen Prefix aufnimmt und so die Whitelists für sämtliche Formulare enthält.

    Die Escape-Anweisung würde ich auch erst nach der Prüfung laufen lassen, ansonsten müsstest du, je nach möglichen Werten, deine erlaubten Werte auch bereits escaped in deinen Code aufnehmen.

    • Bake the Web sagt:

      Genau so ist es Christ, das geht auch genau so.

      Escapen muss ich doch vorher (oft wird es dann vergessen) und ich bin davon ausgegangen das die Vergleichswerte nicht excaped werden müssen.

  • chris sagt:

    btw: bei deinem Formular gewinnt immer die letzte selectbox ;)

  • Kai Neuwerth sagt:

    Schöner Artikel. Ich befasse mich sehr viel mit Web-Security (Schwerpunkt SQLi & XSS).
    Mir ist aufgefallen, dass du vor der switch-Abfrage deine Variabeln escapest… Warum, wenn ich fragen darf?

    Wenn sie manipuliert wurden entsprechen Sie sowieso nicht mehr dem Ursprungswert. Des Weiteren übergibst du dem SQL ja hinterher $ausgabe und nicht mehr $_POST['auswahl']. Ein mysql_real_escape_string() ist für mich daher unnötig oder irre ich mich da?

    Übrigens: Auch mysql_real_escape_string() oder addslashes() kann man austricksen… ;)

    • Bake the Web sagt:

      Hallo Kai, zum Schluss braucht man das in diesem Beispiel nicht mehr das stimmt. Grundsätzlich escape ich alle POST- und vor allem GET-Variablen. Lieber einmal zuviel als einmal zu wenig. Optimieren kann ich immer noch später :-) Die GETs liegen bei meinen Projekten eh immer in den selben Variablen durch die Domainstruktur und werden somit meist direkt im Header excaped. Es lässt sich sicher streiten ob das elegant ist, oder immer erst vor der Verarbeitung zu entscheiden ;-)

      PS: Tipps und Links zu XSS und warum mysql_real_escape_string() nicht reicht, sind hier immer willkommen.

      • Kai Neuwerth sagt:

        Pardon, Links hatte ich vergessen.

        – addslashes()-bypass mit %bf%27: http://bit.ly/dKQOn2
        – mysql_real_escape_string()-bypass: http://bit.ly/HBK94h
        – XSS Cheat Sheet auf welches ich gerne mal zurückgreife: http://bit.ly/1bqjvv

        Aber Programmierer sollten ja sowieso wissen, dass nichts zu 100% sicher ist.

        Um noch mal auf das Thema “SQL-Injections” zu kommen: Ich bevorzuge bei Datenbank-Verbindungen Database-Abstraction-Layers (Adodb, PDO). Dort kann man mit prepared Statements arbeiten und außerdem bieten diese Klassen schon eine Vielzahl an Funktionen, die einem bei der Verarbeitung und Filterung von Daten enorm unter die Arme greifen.
        Natürlich sind diese Klassen sicherheitstechnisch auch bei weitem ausgereifter als irgendwelche Security-Scripts, die man so im Netz findet.

Hinterlasse eine Antwort