GET- und POST-Variablen sicher auslesen

13. Oktober 2013 · Kategorien: Internet, PHP, Webentwicklung

PHP-Elefant

GET- und POST-Variablen können vom Benutzer manipuliert werden und sind deshalb per se unsicher.
Hier stelle ich eine Möglichkeit vor, wie solche Request-Variablen sicherer gehandhabt werden können.

GET- und POST-Variablen auswerten

Nehmen wir an, wir fragen den Benutzer unserer Webseite nach dem Geburtsdatum, das er per Formular einträgt.
Das Geburtsdatum möchten wir darauf vollständig in einer Variable speichern. Das könnte so aussehen:

$birthdate = null;
if(isset($_POST['birthdate_day']) && isset($_POST['birthdate_month']) && isset($_POST['birthdate_year']))
{ 
  $day = $_POST['birthdate_day'];
  $month = $_POST['birthdate_month];
  $year = $_POST['birthdate_year'];
  $birthdate = $day.'.'.$month.'.'.$year;
}

Das hat nun zwei offensichtliche Nachteile:
Zum einen müssen wir für jede POST-Variable überprüfen, dass sie auch wirklich existiert. Bei aktiviertem Error Reporting, das in der Entwicklungsumgebung immer aktiviert sein sollte, würden wir sonst eine Fehlermeldung bekommen.
Für gewöhnlich überprüft man auf Existenz einer Variable mittels isset().
Das kann aber schnell unübersichtlich und auch ziemlich nervtötend sein. Einige Programmierer greifen hierbei auf den @-Operator zurück. Das vergessen wir aber lieber wieder ganz schnell, da in dem Fall nur Fehler unterdrückt werden. Sie sind aber noch da!

GET- und POST-Variablen mit Filterfunktionen validieren

In PHP 5.2 wurden Filterfunktionen hinzugefügt, die es einfacher machen, Request-Variablen zu validieren.
Ein besonders Augenmerk sollten wir auf die Funktion filter_input() richten:

filter_input() erwartet als Argumente den Typ der Requestvariable (also ob GET oder POST), den Namen der Variable und einen Filter, der angewandt werden soll. Unser obiges Beispiel könnte also stattdessen so aussehen:

$birthdate = null;
$day = filter_input(INPUT_POST, 'birthdate_day', FILTER_VALIDATE_INT);
$month = filter_input(INPUT_POST, 'birthdate_month', FILTER_VALIDATE_INT);
$year = filter_input(INPUT_POST, 'birthdate_year', FILTER_VALIDATE_INT);
if($day && $month && $year)
{ 
  $birthdate = $day.'.'.$month.'.'.$year;
}

Nun können wir sicher sein, dass, wenn das $birthdate gesetzt ist, es auch nur Zahlen und Punkte beinhaltet.

Request-Klasse für GET- und POST-Variablen erstellen

Um sich Arbeit zu ersparen, bietet es sich an, eine Request-Klasse zu erstellen. Die könnte zum Beispiel so aussehen:

abstract class Request
{
	public static function get($name, $filter = FILTER_DEFAULT)
	{
		return filter_input(INPUT_GET, $name, $filter);
	}
	
	public static function getInt($name)
	{
		return self::get($name, FILTER_VALIDATE_INT);
	}
	
	public static function getFloat($name)
	{
		return self::get($name, FILTER_VALIDATE_FLOAT);
	}
	
	public static function post($name, $filter = FILTER_DEFAULT)
	{
		return filter_input(INPUT_POST, $name, $filter);
	}
	
	public static function postInt($name)
	{
		return self::post($name, FILTER_VALIDATE_INT);
	}
	
	public static function postFloat($name)
	{
		return self::post($name, FILTER_VALIDATE_FLOAT);
	}
}

Unser Beispiel kann nun so aussehen:

$birthdate = null;
$day = Request::getInt('birthdate_day');
$month = Request::getInt('birthdate_month');
$year = Request::getInt('birthdate_year');
if($day && $month && $year)
{ 
  $birthdate = $day.'.'.$month.'.'.$year;
}

Der Vorteil einer Request-Klasse ist, dass sie zum einen Code verkürzt und sie auch funktionell erweitert werden kann. Zum Beispiel, dass sie auch mehrdimensionale POST-Arrays unterstützt.

Autor: | Kategorien: Internet, PHP, Webentwicklung

7 Kommentare zu GET- und POST-Variablen sicher auslesen

  1. Markus sagt:

    Müsste in der Request-Klasse in Zeile 20 nicht INPUT_POST statt dem INPUT_GET stehen?

  2. olly sagt:

    Hallo,

    getFloat setzt den Filter FILTER_VALIDATE_FLOAT. Aber folgender Wert wird bei mit völlig zerschossen:

    1.234,12 => NULL

    mit FILTER_SANITIZE_NUMBER_FLOAT und FILTER_FLAG_ALLOW_FRACTION bekomme ich folgendes:

    1.234,12 => 1.23412

    Wie bekommt man das in der Griff? Besten dank

    olly

    • Christian Kilb sagt:

      Hey Olly… floats haben keine Tausendertrennzeichen und einen Punkt als Dezimalstelle. Deswegen kommen für Zahlen floats nicht in Frage.
      Du könntest eine Methode getNumber/postNumber implementieren, die mit regulären Ausdrücken oder explode() und intval() die Zahl entsprechend validiert.

  3. sven sagt:

    Hallo,

    mir ist aufgefallen, dass Du in deinen Funktionen das Return vergessen hast.
    Dort steht nur self::…
    Die Klasse kann somit keinen Wert an das PHP Script zurückgeben.

    Sven

Hinterlasse eine Antwort

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