Better safe than sorry

Usereingaben mit der Filter-Erweiterung validieren
Kommentare

Die Sicherheit einer Programmiersprache wird leider oft über die Sicherheitsmängel, in den mit ihr entwickelten Applikationen, definiert. Darunter hat der Ruf von PHP in den letzten Jahren gelitten. Die Filter-Erweiterung wurde ins Leben gerufen, um Standardwerkzeuge bereit zu stellen, mit denen die häufigsten Sicherheitslücken geschlossen werden können.

Einer der größten Vorteile von PHP ist gleichzeitig eine der größten Schwächen unserer Programmiersprache. Die Lernkurve, um mit PHP eine Webanwendung zu erstellen ist sehr niedrig, wodurch es auch Anfängern sehr einfach gemacht wird, Applikationen zu entwickeln und auf Produktivservern zu deployen. Dabei wird der Fokus oft nicht auf Sicherheit gelegt und es kommt zu Schlagzeilen, wie man Sie über die bekannte Forensoftware phpBB lesen musste.

Typische Angriffe

Bevor Sie Ihre Anwendungen gegen Angreifer schützen können, müssen Sie zunächst wissen, wie Angreifer potenzielle Lücken in Ihrer Applikation ausnutzen. Es gibt eine ganze Reihe unterschiedlicher Angriffsarten; gegen manche können Sie sich nur mit Hilfe der richtigen Systemkonfiguration schützen, andere Angriffe richten sich gezielt gegen Fehler, die häufig in der Entwicklung von PHP-Anwendungen gemacht werden. Die Filter-Erweiterung kann Ihnen nur bei den letztgenannten Angriffen helfen und aus diesem Grund werden auch nur diese Arten des Angriffs Thema dieses Artikels sein.

Cross-Site-Scripting

Die Angriffsart, die in den letzten Jahren am meisten von sich reden gemacht hat, ist das so genannte Cross-Site-Scripting, abgekürzt XSS. Dabei versucht ein Angreifer, JavaScript-Code in eine Website einzuschleusen, der dann im Browser des Benutzers ausgeführt wird. Listing 1 zeigt eine PHP-Seite, die typischerweise für Cross-Site-Scripting Angriffe verwendet werden kann.
XSS Beispiel


Name eingeben:
<?php if (isset($_REQUEST[’name‘])) { $name = $_REQUEST[’name‘]; echo “ Hallo {$name}. „; } ?> Wenn Sie die Seite im Browser aufrufen, so wird ein kleines HTML-Formular mit einem Eingabe-Feld angezeigt, in das Sie Ihren Namen eingeben sollen. Wird das Formular abgeschickt, so wird der Name auf der Folgeseite wieder im HTML-Code ausgegeben. Abbildung 1 zeigt die Ausgabe der Folgeseite. Abb. 1: Ein einfaches HTML-Formular mit Eingabefeld Was passiert nun aber, wenn jemand HTML-Code statt eines einfachen Namens in das Formularfeld eingibt? Das einfachste Beispiel, mit dem getestet werden kann, ob eine PHP-Anwendung für Cross-Site-Scripting anfällig ist, ist das folgende HTML-Schnipsel, das Sie in das Formularfeld eintragen:
alert('XSS');
Wenn Sie diese Zeichenkette in das Formular eintragen, dann wird diese auf der Folgeseite mit echo wieder ausgegeben und somit vom Browser als normaler HTML-Code interpretiert. Dabei wird der JavaScript-Code innerhalb der -Tags ausgeführt. Abbildung 2 zeigt Ihnen die Ausgabe des Skriptes, bei einem Cross-Site-Scripting-Angriff. Abb. 2: Das Formular ist anfällig für Cross-Site-Scripting Um diesen Code nun im Browser anderer Nutzer auszuführen, hat ein Angreifer zwei Möglichkeiten:
  • Er bindet auf seiner eigenen Website einen Link ein, der zu Ihrer Seite führt und direkt den name-Parameter übergibt, wie z.B. <a href=“http://www.ihredomain.de/index.php?name=alert“ class=“elf-external elf-icon“ rel=“nofollow“>http://www.ihredomain.de/index.php?name=alert(‚XSS‘);
  • Er bindet auf seiner Seite ein Formular ein, dessen action-Attribut auf Ihre Seite zeigt und übergibt dabei einen versteckten Parameter. Damit führt der Nutzer einen POST-Request auf Ihre Seite aus.
Natürlich wird ein Angreifer Cross-Site-Scripting nicht nutzen, um Info-Boxen mittels alert() auszugeben. JavaScript bietet einem Angreifer aber z.B. auch Zugriff auf Ihre Cookies, aus denen er Session- oder Authentifizierungsinformationen auslesen könnte. Wenn es sich bei der angegriffenen Seite um eine AJAX-Anwendung handelt, so kann der Angreifer auch beliebige AJAX-Anfragen an Ihre Anwendung schicken. Da nicht alle PHP-Programmierer mit den Möglichkeiten von JavaScript vertraut sind, ist vielen die Tragweite von Cross-Site-Scripting noch nicht bewusst.

SQL-Injection

Eine weitere sehr häufig genutzte Angriffsart ist SQL-Injection. Diese macht sich zu Nutze, dass sehr viele PHP-Anwendungen auf relationalen Datenbanken basieren. Der Angreifer versucht dabei schadhaften Code in die SQL-Statements Ihrer Anwendung einzuschleusen. Listing 2 zeigt Ihnen einen Ausschnitt aus einer typischen PHP-Anwendung, die einen News-Eintrag aus einer Datenbank ausliest. Anstatt das Query abzuschicken, wird es für dieses Beispiel nur ausgegeben:
alert('XSS');
Typischerweise rufen Sie dieses Script über einen Link aus Ihrer Anwendung auf und übergeben den Primärschlüssel des News-Eintrags, der angezeigt werden soll. Dazu wird eine URL wie z.B. http://www.ihredomain.de/detail.php?id=35 verwendet. Das Query, das dabei an die Datenbank abgeschickt wird, ist SELECT * FROM news WHERE id=35. Einem Angreifer ist es nun aber ein leichtes, die URL zu manipulieren und z.B. noch die Zeichenkette ;+DELETE+FROM+news; anzuhängen. Dadurch wird das Query verändert und sieht nun folgendermaßen aus:
SELECT * FROM news WHERE id=35; DELETE FROM news;
Das Semikolon markiert hier das Ende eines SQL-Statements, wodurch die Datenbank nun zwei Statements erhält, letzteres löscht alle Einträge aus der Tabelle news. Den Namen der Tabelle kann ein Angreifer schnell erraten oder eventuell durch provozieren von Fehlermeldungen erfahren.

Parametermanipulation

Beide vorgestellten Angriffe basieren auf dem Prinzip der Parameter-Manipulation und stellen eher einfache Angriffe dar. Neben GET-Parametern ist es versierten Angreifern ein Leichtes, andere Parameter des HTTP-Requests zu manipulieren, und SQL-Injections z.B. durch Verändern des User-Agents oder der Cookies durchzuführen. Dieser erste Teil des Artikels konnte also nur an der Oberfläche der verschiedenen Angriffe kratzen und Sie für die möglichen Angriffsarten sensibilisieren. Weitere Informationen zu verschiedenen Angriffsarten finden Sie im Buch „PHP Sicherheit“ [1] der Autoren der Sicherheits-Kolumne im PHP-Magazin. Selbst fortgeschrittene PHP-Entwickler dürften in diesem Buch noch auf Sicherheitslücken in ihren eigenen Applikationen aufmerksam werden. Grundsätzlich ist es wichtig zu wissen und zu verstehen, dass alles, was aus dem so genannten Userland kommt, potentiell Schadcode enthalten kann, der Ihre Anwendung angreift. Sie sollten sich nie darauf verlassen, dass die Werte, die vom Client an Ihre Anwendung geschickt werden, so aussehen, wie Sie sie erwarten. So kann es auch sein, dass ein User-Agent-String oder der Hostname in $_SERVER[‚HTTP_HOST‘] JavaScript-Code enthalten, der von Ihnen wieder zurück an den Client geschickt wird, wo dieser dann ausgeführt wird. Auch sollten Sie sich nie auf Client-seitige Validierungen verlassen, die Sie per JavaScript durchführen, da dieses problemlos deaktiviert oder modifiziert werden könnte. Und sollte ein Parameter im Frontend durch einen -Tag ausgewühlt werden müssen, so reicht auch dies nicht als Validierung aus, da entweder das HTML-Formular verändert worden sein könnte, oder ein Angreifer ein Tool wie Tamper-Data für Firefox verwenden könnte, mit dem alle Parameter eines HTTP-Requests modifiziert werden können, bevor er abgeschickt wird.

Die Funktionen der Filter-Erweiterung

Die Filter-Erweiterung wurde ins Leben gerufen, um den Angriffen, die auf Parameter-Manipulation basieren, einen Riegel vorzuschieben. Dazu bietet die Erweiterung verschiedene Filter, mit denen verschiedene Parameter-Typen gefiltert werden können. Unterstützt werden dabei einfache Typen wie Integer- oder Boolesche Werte, aber auch URLs oder E-Mail-Adressen können leicht überprüft werden. Im Gegensatz zu vielen anderen PHP-Erweiterungen bietet die Filter-Extension nicht eine Funktion pro Filter an, sondern beschränkt sich auf eine recht geringe Anzahl von sieben PHP-Funktionen. Die einzelnen Filter sind über Konstanten ansprechbar, die an die verschiedenen Funktionen der Filter-API übergeben werden. Dabei kann die Filter-API nur prozedural und nicht objektorientiert genutzt werden, was gerade im Hinblick darauf, dass sie speziell für PHP Versionen ab 5.1 implementiert wurde, sehr schade und nicht gerade verständlich ist.
Installation von ext/filter Wenn Sie zu den Glücklichen gehören, die bereits mit PHP 5.2.x arbeiten können, dann brauchen Sie sich um die Installation der Filter-Extension nicht zu kümmern, da diese bereits mit PHP ausgeliefert wird. Sollten Sie mit einer Version vor PHP 5.1 arbeiten, so können Sie die Erweiterung leider gar nicht nutzen, da diese erst ab PHP 5.1 lauffähig ist. Um die Filter-Erweiterung nachzuinstallieren, verwenden Sie den PECL-Installer: $ pecl install pecl/filter Alternativ können Sie den Sourcecode auch von der PECL-Website herunterladen und selbst kompilieren. Sollten Sie mit Windows arbeiten, so können Sie sich auch eine DLL der Erweiterung von der PECL4Win-Website herunterladen und in das Extensions-Verzeichnis Ihrer PHP-Installation kopieren. Aktiviert wird die Erweiterung dann durch den entsprechenden Eintrag in der php.ini.

Usereingaben filtern

Als erstes verwenden Sie nun die Filter-Erweiterung, um die SQL-Injection aus dem zweiten Beispiel zu verhindern. Das Problem hierbei war, dass Sie einen numerischen Primärschlüssel erwartet, jedoch einen String mit zusätzlichen SQL-Anweisungen erhalten haben.
Konstante Herkunft der Daten
INPUT_GET Per GET übergebene URL-Parameter ($_GET)
INPUT_POST Daten aus einem POST-Request ($_POST)
INPUT_COOKIE Cookies des Clients ($_COOKIE)
INPUT_SERVER Servervariablen ($_SERVER)
INPUT_ENV Environment-Variablen ($_ENV)
Tabelle 1: Quellen der Userland-Daten Die Filter-Erweiterung stellt eine Funktion zur Verfügung, mit der Sie auf Daten aus dem HTTP-Request zugreifen und dabei diese Werte gleichzeitig filtern können. Diese Funktion verwenden Sie nun, statt die Id direkt über die superglobale Variable $_GET direkt aus den GET-Parametern zu holen. Die Funktion, die Sie dazu nutzen, heißt filter_input() und erwartet die folgenden Parameter:
    • Herkunft des zu filternden Wertes (Tabelle 1 zeigt Ihnen eine Übersicht der möglichen Werte)
    • Name des Wertes (z.B. des GET-Parameters), der gefiltert werden soll
    • Konstante für den Filter, der angewandt werden soll
    • Optionen und Flags für den Filter (optional)
Wollen Sie nun den Parameter id aus den Parametern holen, die per GET übermittelt wurden und dabei nur einen Integer-Wert erhalten, so verwenden Sie den folgenden Funktionsaufruf:
filter_input(INPUT_GET, 'id', FILTER_SANITIZE_NUMBER_INT);
Die Konstante INPUT_GET gibt an, dass ein GET-Parameter gefiltert werden soll, mit dem String id definieren Sie den Namen des zu filternden Parameters und die KonstanteFILTER_SANITIZE_NUMBER_INT definiert letztlich, dass der Filter nur den Integer-Wert durchlassen soll und alle anderen Zeichen verworfen werden. Listing 3 zeigt Ihnen, wie das Skript aus dem Beispiel unter Verwendung der Filter-Funktionen aussehen muss. Wenn Sie nun die manipulierte URL aufrufen, werden Sie erkennen, dass das ausgegebene Query keinen Schadcode mehr enthält, sondern lediglich die Id, die übergeben wurde.

Wenn Sie sich die verschiedenen Optionen für die Herkunft der zu filternden Parameter anschauen, so werden Sie feststellen, dass diese nahezu identisch mit den superglobalen Variablen sind und lediglich die Entsprechungen für die folgenden Superglobalen fehlen:
      • $_SESSION, da es sich bei Werten in der Session nicht um Benutzereingaben handelt, diese also nicht als unsicher gelten.
 
  • $_FILES, da die Filter-Erweiterung nicht in der Lage ist, Dateien zu filtern.
   
  • $_REQUEST, da beim Filtern immer darauf geachtet werden sollte, dass eine Variable nur aus der Quelle akzeptiert wird, aus der Sie sie erwarten. Somit können Sie es Angreifern schwerer machen, Parameter in Ihre Anwendungen einzuschleusen, da Attacken wie Cross-Site-Request-Forgeries (CSRF) erschwert werden.
     

Filtern vs. Validieren

Durch den Einsatz der Filter-Erweiterung haben Sie es nun geschafft, die SQL-Injection-Attacke abzuwehren, aber der Versuch ging wie eine normale Anfrage an Ihre Applikation durch, obwohl es sich bei der Anfrage um einen ungültigen Request gehandelt hat. Der Filter FILTER_SANITIZE_NUMBER_INT hat einfach nur alle Zeichen, die nicht Teil eines Integer-Wertes sein können, aus dem Parameter entfernt. Besonders deutlich wird dies, wenn Sie den folgenden Query-String an den Aufruf der Seite anhängen: ?id=35;+DELETE+FROM+news;+42 . Das SQL-Query, das dabei abgeschickt wird, ist nun:
SELECT * FROM news WHERE id=3542
Der Mittelteil des Parameters wurde einfach entfernt, aber alle Ziffern wurden vom Filter so belassen, wie sie sind, wodurch der Parameter nach dem Filtern den Wert 3542 angenommen hat. Der Filter hat den Parameter nur gereinigt, in dem ungültige Zeichen entfernt wurden. Auch wenn dies keine Gefahr mehr darstellt, wäre es doch besser, wenn Sie auf einen ungültigen Wert nicht mit dem Versuch einer SQL-Abfrage reagieren würden. Dazu bietet die Erweiterung neben den reinigenden Filtern auch noch validierende Filter an. Die validierende Entsprechung zum Integer-Filter ist FILTER_VALIDATE_INT. Verwendet wird dieser genau so, wie der bisherige Filter:
filter_input(INPUT_GET, 'id', FILTER_VALIDATE_INT);
Wenn Sie den bisherigen Filter durch diesen Filter ersetzen, und dann versuchen, die SQL-Injection einzuschleusen, erhalten Sie das folgende Query:
SELECT * FROM news WHERE id=
Dies liegt daran, dass validierende Filter den Booleschen Wert false zurück liefern, sobald der Parameter nicht den gewünschten Kriterien entspricht. Bevor Sie das Query erstellen und abschicken, sollten Sie in diesem Fall also den Rückgabewert der filter_input()-Methode überprüfen. Listing 4 zeigt Ihnen, wie das komplette Skript aussehen könnte. Statt dem Aufruf derdie()-Funktion sollte das Fehlerhandling in Ihrer Anwendung zum Einsatz kommen.

 

Vorhandene Filter

Die Filter-Erweiterung bietet eine Möglichkeit, die Liste der vorhandenen Filter zu ermitteln. Damit sind Sie in der Lage Ihre Applikationen abwärtskompatibel zu halten, in dem Sie vor dem Einsatz eines Filters überprüfen können, ob dieser in der installierten PHP-Version verfügbar ist. Um auszugeben, welche Filter in Ihrer PHP-Version verfügbar sind, verwenden Sie den folgenden Code:
$filters = filter_list();
print_r($filters);
Die Ausgabe dieses Code-Schnipsels sieht dann folgendermaßen aus:
Array
(
[0] => int
[1] => boolean
[2] => float
...
[16] => magic_quotes
[17] => callback
)
Je nach installierter Version ist das Array größer oder kleiner als die hier gezeigten Einträge. Das Array enthält die Namen aller verfügbaren Filter. Diese sind jedoch nicht identisch mit den Konstanten, die Sie an die Funktion filter_input() übergeben haben. Wollen Sie von einem Filter-Namen auf die Id des Filters kommen, so verwenden Sie die Funktion filter_id(). Der folgende PHP-Code gibt die Namen und Ids aller verfügbaren Filter aus:
$filters = filter_list();
foreach ($filters as $filterName) {
$filterId = filter_id($filterName);
printf("%s : %dn", $filterName,
$filterId);
}
Eine kurze Beschreibung aller Filter finden Sie in den Tabellen 2 und 3, aufgeteilt in validierende und reinigende Filter.
Name Id Konstante Beschreibung
int 257 FILTER_VALIDATE_INT Validiert Wert als Integer-Zahl
boolean 258 FILTER_VALIDATE_BOOLEAN Interpretiert einen Wert als Booleschen Wert („true“, „yes“ und „on“ werden zu true)
float 259 FILTER_VALIDATE_FLOAT Validiert Wert als Fließkommazahl
validate_regexp 272 FILTER_VALIDATE_REGEXP Validiert Wert mit Hilfe eine regulären Ausdrucks
validate_url 273 FILTER_VALIDATE_URL Überprüft, ob der Wert eine gültige URL ist
validate_email 274 FILTER_VALIDATE_EMAIL Überprüft, ob der Wert eine syntaktisch korrekte E-Mail-Adresse ist
validate_ip 275 FILTER_VALIDATE_IP Überprüft, ob der Wert eine syntaktisch korrekte E-Mail-Adresse ist
Tabelle 2: Validierende Filter
Name Id Konstante Beschreibung
string 513 FILTER_SANITIZE_STRING Entfernt Tags und kann Zeichen in HTML-Entities umwandeln
stripped 513 FILTER_SANITIZE_STRIPPED Alias für FILTER_SANITIZE_STRING
encoded 514 FILTER_SANITIZE_ENCODED URL-kodiert Strings
special_chars 515 FILTER_SANITIZE_SPECIAL_CHARS Ersetzt HTML-Sonderzeichen durch Entities
unsafe_raw 516 FILTTER_UNSAFE_RAW Dummy-Filter, filtert keine Werte
email 517 FILTER_SANITIZE_EMAIL Entfernt ungültige Zeichen aus E-Mails
url 518 FILTER_SANITIZE_URL Entfernt ungültige Zeichen aus URLs
number_int 519 FILTER_SANITIZE_NUMBER_INT Filtert ungültige Zeichen aus Integer-Werten
number_float 520 FILTER_SANITIZE_NUMBER_FLOAT Erzeugt syntaktisch korrekte Fließkommazahl
magic_quotes 521 FILTER_SANITIZE_MAGIC_QUOTES Agiert als Alias für die Funktion addslashes()
callback 1024 FILTER_CALLBACK Delegiert die Validierung an eine Callback-Funktion
Tabelle 3: Reinigende Filter Nachdem Sie jetzt alle Filter der Erweiterung kennen, können Sie diese auch verwenden, um die Cross-Site-Scripting-Attacke aus dem ersten Beispiel abzuwehren. Dazu können Sie den Filter FILTER_SANITIZE_STRING verwenden, der HTML-Tags aus dem Parameter entfernt. Listing 5 zeigt Ihnen das modifizierte Skript.
XSS Beispiel


Name eingeben:
<?php if (filter_has_var(INPUT_POST, ’name‘)) { $name = filter_input(INPUT_POST, ’name‘, FILTER_SANITIZE_STRING); echo “ Hallo {$name}. „; } ?> Anstatt auf $_REQUEST[’name‘] zuzugreifen, wird auch hier die Funktion filter_input() verwendet und dafür gesorgt, dass HTML-Tags nicht wieder ausgegeben werden.
Superglobale Variablen vs. Filter-Funktionen Bei der Arbeit mit der Filter-Erweiterung sollte Ihnen bewusst sein, dass die filter_*-Funktionen nicht mit den Inhalten der superglobalen Variablen arbeiten, sondern mit den ursprünglichen Daten des Requests. Wenn Sie also die Daten in $_GET verändern und dann mit filter_input() darauf zugreifen, so erhalten Sie nicht die modifizierten Werte zurück. Aus diesem Grund bietet die Filter-Erweiterung auch noch die Funktionfilter_has_var(), mit der Sie überprüfen können, ob ein Wert vorhanden ist. Die Funktion dient als Ersatz für isset($_GET[’name‘]); Wozu die Funktion filter_has_var() in diesem Beispiel verwendet wird, entnehmen Sie dem Kasten „Superglobale Variablen vs. Filter-Funktionen“.

Optionen und Flags

Viele der Filter ermöglichen es Ihnen, über Optionen und Flags das Verhalten zu steuern. Möchten Sie z.B. nur Integer-Werte zwischen 0 und 1000 erlauben, so definieren Sie dies über die Optionen min_range und max_range des FILTER_VALIDATE_INT Filters. Optionen werden in einem assoziativen Array als vierter Parameter an die Funktion filter_input() übergeben. Dieses Array kann zwei Keys enthalten:
    • options muss ein weiteres assoziatives Array enthalten das die einzelnen Optionen definiert
    • flags enthält einen Integer-Wert, den Sie aus verschiedenen Konstanten zusammensetzen können
Der folgende Code ist nötig, um den möglichen Bereich für die übergebene Ganzzahl einzugrenzen:
$options = array(
'options' => array(
'min_range' => 0,
'max_range' => 1000
)
);
$newsId = filter_input(INPUT_GET, 'id', FILTER_VALIDATE_INT, $options);
Wenn Sie nun das Skript mit dem Query-String ?id=1001 aufrufen, erhalten Sie die Meldung, dass eine ungültige Id übergeben wurde. Möchten Sie beim Filtern von HTML-Tags auch sicherstellen, dass Zeichen mit hohen oder niedrigen ASCII-Codes in ihre entsprechenden HTML-Entities umgewandelt werden, so verwenden Sie dazu die FlagsFILTER_FLAG_ENCODE_LOW und FILTER_FLAG_ENCODE_HIGH und übergeben diese an den entsprechenden Filter:
$options = array(
'flags' => FILTER_FLAG_ENCODE_HIGH | FILTER_FLAG_ENCODE_LOW
);
$name = filter_input(INPUT_POST, 'name', FILTER_SANITIZE_STRING, $options);
Geben Sie jetzt einen Namen mit Umlauten ein, z.B. Björn, so werden die Umlaute korrekt als HTML-Entities kodiert und die Ausgabe ist:
Hallo Björn.
Besonders die Filter zum Filtern und Validieren von Fließkommazahlen, URLs und IP-Adressen bieten sehr viele Flags, die das Verhalten beeinflussen. So ist es z.B. möglich zu definieren, ob auch private IP-Netze erlaubt werden sollen oder nicht. Leider ist nicht intuitiv zu bestimmen, welche Möglichkeiten der Einflussnahme über Optionen und welche über Flags gesteuert werden. Die einfachste Regel ist, dass Flags immer dann eingesetzt werden, wenn ein Feature nur aktiviert werden muss und kein zusätzlicher Parameter an die Option übergeben werden muss. Eine Liste der möglichen Optionen und Flags für die einzelnen Filter finden Sie in der Dokumentation im PHP-Manual.

Usereingaben automatisch filtern

Ein interessantes Feature der Filter-Erweiterung ist die Möglichkeit, dass alle Parameter, die aus dem Userland in die superglobalen Variablen importiert werden, durch einen Default-Filter geschleust werden können. Diesen Default-Filter können Sie in der php.ini oder in einer .htaccess-Datei pro Verzeichnis festlegen. Dazu wird die neue Konfigurationsoption filter.default bereit gestellt. Diese setzen Sie allerdings nicht auf die Konstante für die Filter-Id sondern auf den Namen des Filters, wie er von der Funktion filter_list() zurück gegeben wird. Möchten Sie also, dass für alle Parameter HTML-Tags entfernt werden, so fügen Sie diesen Eintrag zu Ihrer php.ini Datei hinzu:
filter.default = stripped
Weiterhin ist es möglich, über die Option filter.default_flags Flags für den definierten Filter zu übergeben. Die folgende Zeile sorgt dafür, dass Zeichen mit hohen oder niedrigen ASCII-Werten durch Entities ersetzt werden:
filter.default_flags = 48
Mit Hilfe dieses Features kann es Ihnen in manchen Fällen gelingen, eine unsichere Anwendung wenigsten Teilweise abzusichern, da die Werte in den superglobalen Variablen, mit denen Ihre Applikation arbeitet, bereits gefiltert wurden. Über die Funktion filter_input() können Sie weiterhin auf die ungefilterten Werte zugreifen.

Vorhandene Daten filtern

Die Filter-Erweiterung stellt Ihnen die Filter nicht nur für die Parameter zur Verfügung die von außen an Ihre Anwendung übergeben wurden, sondern erlaubt Ihnen auch, die verschiedenen Filter auf beliebigen PHP-Variablen anzuwenden. Dafür bietet die Erweiterung die Funktion filter_var(), deren Signatur sehr stark an filter_input() erinnert:
    • Als ersten Parameter übergeben Sie die PHP-Variable, die gefiltert werden soll.
    • Als zweiten Parameter übergeben Sie die Konstante für den zu verwendenden Filter.
    • Als dritten Parameter übergeben Sie optional weitere Flags und Optionen.
Möchten Sie also eine URL, die Sie aus einer beliebigen Quelle erhalten haben, auf Gültigkeit überprüfen, so verwenden Sie dazu den folgenden Code:
$url = 'http://www.example.com';
var_dump(
filter_var($url, FILTER_VALIDATE_URL, FILTER_FLAG_SCHEME_REQUIRED |
FILTER_FLAG_SCHEME_REQUIRED)
);
Dieser Code zeigt Ihnen auch gleichzeitig noch eine verkürzte Schreibweise für die Übergabe von Flags an einen Filter. Möchte man keine zusätzlichen Optionen übergeben, so können Sie die Flags direkt als dritten Parameter übergeben, ohne diese in ein Array verpacken zu müssen. Wenn Sie den URL-Filter verwenden möchten, so sollten Sie immer daran denken, über die Flags zu definieren, welche Teile der URL zwingend erforderlich sind, da die URL-Validierung ansonsten sehr wenig restriktiv ist. Der Filter ermöglicht Ihnen aber z.B. auch zu erzwingen, dass die URL einen Query-String haben muss:
var_dump(
filter_var($url, FILTER_VALIDATE_URL, FILTER_FLAG_SCHEME_REQUIRED |
FILTER_FLAG_SCHEME_REQUIRED |
FILTER_FLAG_QUERY_REQUIRED)
);
Diese Validierung schlägt natürlich fehl und der Filter wird in diesem Fall den Wert false zurück liefern.

Die Filter-Extension durch Callbacks erweitern

Sollte die Filter-Erweiterung eine Validierungsregel, die Sie benötigen, noch nicht anbieten, so können Sie diese recht einfach über Callbacks integrieren. Ein Callback kann eine PHP-Funktion oder auch eine -Methode sein. Diese muss als einzigen Parameter den zu validierenden Wert akzeptieren und sollte entweder den bereinigten Wert oder den Booleschen Wertfalse zurück liefern, falls der Wert nicht erfolgreich validiert werden konnte. Listing 6 zeigt eine solche Callback-Funktion, die einen typischen Whitelist-Check durchführt, in dem Sie überprüft, ob der übergebene Wert in einer zuvor definieren Liste enthalten ist.
XSS Beispiel


Name eingeben:
‚checkWhitelist‘)); echo “ Hallo {$name}. „; } ?> Damit die Filter-Erweiterung Ihre Funktion aufruft, wenden Sie den FILTER_CALLBACK-Filter an und übergeben statt einem Array mit Optionen einfach den Namen der Callback-Funktion. Dieser Filter delegiert die Validierung dann an Ihre Methode weiter. Sie mögen sich nun vielleicht fragen, warum Sie die Funktion nicht direkt aufgerufen haben, sondern dies über die Funktion filter_input() machen sollten. Dies hat zwei Vorteile:
Sie verwenden eine konsistente API für alle Validierungen.
Sie verwenden keine ungefilterten Werte in Ihren Anwendungen und greifen nie auf die superglobalen Variablen zu.
Der Callback-Filter ermöglicht es Ihnen also bis zu einem gewissen Grad, eigene Filter zu implementieren. Leider ist es bislang nicht möglich, Optionen oder Flags an diese Userland-Filter zu übergeben.

Weitere Features

In diesem Artikel haben Sie nun fast alle Features der neuen Filter-Erweiterung kennen gelernt. Natürlich konnten nicht alle Filter im Detail demonstriert werden, aber die Arbeitsweise beim Filtern der Daten ist unabhängig vom verwendeten Filter; Sie müssen sich beim Einsatz anderer Filter nur mit den entsprechenden Optionen und Flags vertraut machen. Neben der Möglichkeit, einen einzelnen Wert zu validieren oder zu filtern, bietet die Extension auch noch die Funktionen filter_input_array() und filter_var_array(), mit der mehrere Werte auf einmal verarbeitet werden können. Weitere Informationen, welche Parameter an diese Funktionen übergeben werden können, finden Sie im PHP-Manual.

Fazit

Die Filter-Erweiterung ist ein großer Schritt für die Sicherheit von PHP-Anwendungen, da die Integration in den Core jedem Entwickler ein Werkzeug an die Hand gibt, mit dem sehr einfach die wichtigsten Validierungen durchgeführt werden können. Die Extension wird sicherlich einigen Entwicklern, die sich bislang wenig um die Sicherheit ihrer Anwendungen gekümmert haben, den Einstieg in dieses Thema erleichtern. Leider hat die Erweiterung auch noch einige Schwächen, die bislang dafür gesorgt haben, dass sie nicht die nötige Akzeptanz unter den PHP-Entwicklern erreicht hat. Zum einen ist dies die doch sehr gewöhnungsbedürftige API, bei der sich der Entwickler die Namen sehr vieler Konstanten und Optionen merken muss und bei denen sich leicht Schreibfehler einschleichen können. Auch die nicht immer ganz logische Aufteilung in Optionen und Flags macht die Bedienung nicht gerade intuitiv. Zum anderen ist die Erweiterung noch am Anfang der Entwicklung, so kam es in den letzten PHP-Versionen nochmal zu Umbenennungen in den Funktionsnamen, was Probleme machte, wenn man eine Anwendung installiert hatte, die noch die alten Namen der Funktionen verwendete. Sollten Sie das Thema Eingabevalidierung in Ihren Anwendungen bislang vernachlässigt haben und somit noch keine eigene Komponente geschrieben haben, die sich um die Validierung der Parameter kümmert, so ist es auf jeden Fall ratsam, die Filter-Erweiterung einzusetzen. Sie sollten sich jedoch auch immer darüber im Klaren sein, dass der Einsatz der Filter-Erweiterung alleine noch nicht dafür sorgt, dass Ihre Anwendungen gegenüber allen Angriffen sicher sind. Auch hier sei noch einmal auf das ausgezeichnete Buch „PHP Sicherheit“ [1] verwiesen, in dem Sie viele wertvolle Tipps zum Absichern Ihrer Anwendungen finden. Weiterhin kann auch der Einsatz eines Security-Scanners wie Chorizo! helfen, Lücken zu finden, die man selbst übersehen kann. Weitere Informationen zur Filter-Erweiterung finden Sie in den kostenlosen (englischsprachige) Tutorials im Netz [Link 1], [Link 2].
Unsere Redaktion empfiehlt:

Relevante Beiträge

Meinungen zu diesem Beitrag

X
- Gib Deinen Standort ein -
- or -