Wie man request_var (nicht) benutzen sollte

Hier gibt es sporadisch Tipps zur Programmierung für phpBB3.0.x MOD Autoren
Antworten
Benutzeravatar
Mahony
Site Admin
Site Admin
Beiträge: 792
Registriert: 3. Dez 2006 22:09
Hat sich bedankt: 22 Mal
Danksagung erhalten: 6 Mal

Wie man request_var (nicht) benutzen sollte

Beitrag von Mahony »

Hinweis: Dieser Beitrag richtet sich gezielt an MOD Autoren und enthält viele technische Details.

Einführung

Eines der großen Sicherheits-Features, die phpBB 3.0 bietet, ist die Funktion für die Verarbeitung von Benutzereingaben, request_var. Diese Funktion wurde entwickelt, um einfach und sicher vom Benutzer eingegebene Daten abzurufen(zu verarbeiten.
Eine der wichtigsten Sicherheitsfunktionen in einem System, das externe Daten verarbeitet, ist es XSS und SQL-Injection-Angriffe im Ansatz zu stoppen. request_var macht genau dieses (mit Einschränkungen, die wir weiter unten noch erarbeiten werden).
Aus diesem Grund wurde die Anleitung erstellt wie request_var funktioniert und warum man es verwenden sollte.

SQL Injections

SQL Injections sind eine der gefährlichsten Sicherheitslücken die Web-Anwendung haben können, sie sind jedoch relativ einfach zu verhindern. Diese Angriffe sind immer dann erfolgreich, wenn Daten in die Datenbank gelangen, ohne dass sie zuvor korrekt bereinigt wurden. Alle Benutzereingaben die aus den $ _GET, $ _POST, $ _COOKIE und $ _SERVER Arrays kommen müssen korrekt bereinigt werden.

Um SQL Injections in phpBB 3.0 zu vermeiden, ist die richtige Anwendung der Typisierung von request_var erforderlich.


Daten Eingabe und Typisierung

Um SQL Injections in nicht String Typen (int) zu verhindern, ist es wichtig den richtigen Datentyp bereits während der Eingabe zu setzen. Es ist absolut entscheidend, sicherzustellen dass der Typ angegeben ist, der auch erwartet wurde.

In request_var, geschieht dies durch das setzen des zweiten Arguments, dem default Wert, der von dir benötigt wird.



Beispiel zur Nutzung von request_var

Hier ein Beispiel für die Verwendung von request_var. Das Beispiel enthält Benutzereingaben bei Verwendung von request_var und startet eine SQL-Abfrage darauf basierend. Beachte die 0 in der request_var Verwendung, diese stellt sicher, dass $user_id eine Zahl (int) ist.

Code: Alles auswählen

$user_id = request_var('user_id', 0);

$sql = 'SELECT username
FROM ' . USERS_TABLE . '
WHERE user_id = ' . $user_id;
$result = $db->sql_query($sql);
$row = $db->sql_fetchrow($result);
$db->sql_freeresult($result);

echo $row['username'];

Was dabei schief gehen kann

Hier ein Beispiel für einen Fehler, der sehr böse Folgen haben kann. Das Beispiel basiert auf dem vorherigen Beispiel. Anstelle des default Wertes 0, nutzen wir die user_id des aktuellen Benutzers als Standard.

Code: Alles auswählen

$user_id = request_var('user_id', $user->data['user_id']);

$sql = 'SELECT username
FROM ' . USERS_TABLE . '
WHERE user_id = ' . $user_id;
$result = $db->sql_query($sql);
$row = $db->sql_fetchrow($result);
$db->sql_freeresult($result);

echo $row['username'];
Wie du siehst, wurde lediglich die erste Zeile geändert.


Die Sicherheitslücke

Hast du es bemerkt? $user->data['user_id'] ist ein Wert, der direkt aus der Datenbank stammt und alle Werte aus der Datenbank sind Zeichenketten (Strings). Dies bedeutet, $user_id wird nicht in einen Integer Wert (Zahl) umgewandelt, sondern in einen String (Zeichenkette). Die Folge ist, dass ein Angreifer die SQL-Abfrage für den eigenen Gebrauch ändern und an die Datenbank senden kann.

Wenn ein Angreifer zum Beispiel eine E-Mail-Adresse auslesen möchte, müsste er einfach nur den GET-Parameter für user_id folgendermaßen ändern:

Code: Alles auswählen

0 UNION SELECT user_email as username FROM phpbb_users WHERE user_id = 2
Dies würde dann zu folgender SQL-Abfrage an die Datenbank führen:

Code: Alles auswählen

SELECT username FROM phpbb_users WHERE user_id = 0 UNION SELECT user_email as username FROM phpbb_users WHERE user_id = 2
Das Ergebnis, wäre die Ausgabe der E-Mail Adresse des Benutzers mit der user_id 2. Es sollte also klar sein, dass ein Angreifer mit einer solchen Methode noch wesentlich mehr Schaden anrichten kann.



Wie man es richtig macht

Es ist extrem einfach, sich vor solchen Angriffen zu schützen. Es ist lediglich nötig, das zweite Argument von request_var als integer (Zahl) zu setzen.
Im Code würde dies wie folgt aussehen:

Code: Alles auswählen

$user_id = request_var('user_id', (int) $user->data['user_id']);

Noch eine Anmerkung zu Strings

Obwohl request_var, bei bestimmungsgemäßer Verwendung, in der Lage ist dich gegen die meisten Arten solcher Angriffe zu schützen, gibt es noch eine weitere Bedingung, wenn eine Zeichenfolge (String) angefordert/abgefragt wird.
Diese Bedingung, besteht darin die String - Daten (Zeichenketten) korrekt für die Datenbank zu escapen. Dazu verwendet man die sql_escape function im database object wie folgt:

Code: Alles auswählen

$foo = request_var('foo', 'bar');
$sql = 'SELECT username
FROM ' . USERS_TABLE . '
WHERE foo = ' . $db->sql_escape($foo);

Das war es!

request_var ist ein großartiges Tool, es muss aber auch ordnungsgemäß verwendet werden, das Casting (setzen) der Standardwerte auf den richtigen Typ und das escapen von Strings ist elementar, bevor du sie in einer SQL-Abfrage abschickst.

Dieser Artikel basiert auf dem Artikel des phpbb.com - blogs

Weitere Quellen:
Diejenigen, die lautstark darüber diskutieren, warum es nicht geht, mögen bitte jene nicht stören, die es gerade tun.
Klug ist, wer nur die Hälfte von dem glaubt, was er hört. Weise ist, wer erkennt, welche Hälfte richtig ist.

Bild
Antworten