Einst war es zu einfach, in PHP unsicheren Code zu schreiben. Das hat sich mit PHP 4.1 geändert.

Wichtigste Neuerung von PHP 4.1 war das neue Übergabeverfahren für Userdaten von Formular oder Cookie zum Programm. Bislang setzt aber kaum ein Provider den Wert register_globals auf off. Doch es lohnt sich dennoch, umzusteigen. Denn mit der neuen Art der Variablenübergabe kann man sich eine Menge Ärger sparen.

Dieser Beitrag zeigt, wie man damit umgeht.

Neues Übergabeverfahren für Userdaten

PHP hat eine angenehme Eigenschaft: Per GET oder POST aus Formularen übergebene Werte gelten im aufgerufenen PHP-Programm automatisch als globale Variablen. Das bedeutet: Theoretisch lassen sich über jeden Aufruf eines PHP-Programms in der URL beliebige Variablen ins Programm schmuggeln. Das mag zwar meist erwünscht sein, führt andererseits bei unsauberer Programmierung schnell zu Problemen.

Das folgende Beispiel verdeutlicht die Schwachstellen. Ein Formular ruft die Datei global.php auf und übergibt ihr per POST den Inhalt des Eingabefeldes als Variable hallo.

<form action="global.php" method="POST">

<input type="text" name="hallo"></input>

<input type=submit>

</form>

Das Programm global.php enthält gerade einen Befehl:

<?

echo $hallo;

?>

Ein Klick auf den Submit-Button übergibt hallo aus dem Formular ins Programm. global.php zeigt brav den Wert der Variablen. Doch hier sitzt eine Sicherheitslücke sein: Denn genauso kann jemand die Datei mit http://foo.bar/global.php?hello=Oh+ich+Hacker aufrufen und Daten manipulieren.

Besonders nachlässige Programmierer haben dann ein Problem, wenn Sie in der verarbeitenden Datei keine Prüfroutine vor die Verwendung der Variablen geschaltet haben. Auf diese Weise lassen sich beispielsweise ganz einfach Javascript-Prüfroutinen in Formularen aushebeln.

Schlimmeres droht, wenn in IF-Konstruktionen Variablen gesetzt werden und wenn diese Variablen vorher nicht sauber initialisiert sind. Ein Beispiel:

<?

if (1 == 2)

{

$wichtig = 10;

}

echo $wichtig;

?>

In diesem Beispiel ist bewusst eine unmögliche Bedingung eingebaut. Das if kann in keinem Fall wahr sein, die Variable $wichtig bleibt ohne Wert. Ruft aber jemand diese Datei mit beispiel.php?wichtig=10 auf, erhält die Variable trotzdem einen Wert.

Natürlich sind solche Sicherheitslücken nicht Schuld der globalen Registrierung von Variablen. Aber die Registrierung erleichtert das Entstehen solcher Fehler. Das soll sich alles ändern. PHP 4.1 will Fehlerquellen ausschließen und bietet einen neuen Eingabemechanismus an. „Bietet an“ bedeutet: Noch ist die globale Registrierung der übergebenen Variablen nicht ausgeschaltet. Und das neue Verfahren soll das alte nur ergänzen, jedoch nie verdrängen.

Also Entwarnung: Niemand muss sofort Code umschreiben. Allerdings soll mit der nächst größeren Version der Eintrag register_globals in php.ini per Default deaktiviert sein. Sprich: wer mit einem späteren PHP einsteigt, wird zum neuen Verfahren erzogen.

Das neue Übergabeverfahren besteht aus einem Satz von speziellen Arrays. Je nach Art der Datenübergabe erhält das entsprechende Array die Daten.

Die Arrays sind:

$_GET - für Formulareinträge, die per GET, also über die URL weiter gegeben werden

$_POST - für Formulareinträge, die per POST, also für den Nutzer unsichtbar übergeben werden

$_COOKIE - für Variablen die aus Cookies kommen

$_SERVER - für Servervariablen

$_ENV - für Umgebungsvariablen

$_REQUEST - speichert die per GET, POST und in COOKIES übergebenen Daten. Das ist der flexibelste Weg, vom User übergebene Daten einzulesen.

$_SESSION - enthält HTTP-Session-Variablen aus den Modulen

Für den Programmierer bedeutet das: eine übergebene Variable steht nicht sofort global zur Verfügung. Um die Variable ins Programm zu übernehmen muss man sie aus dem Array fischen. Allein dieser Schritt bringt viel Sicherheit. Denn der Programmierer muss bestimmen, woher das Programm die Variable und wo ihr Inhalt schließlich landet. Ein Beispiel:

$my_hallo = $_POST["hallo"];

echo $my_hallo;

Hier wird die Variable hallo nur dann angenommen und $my_hallo zugewiesen, wenn hallo aus einem POST-Formular kommt. Das schließt alle Hack-Versuche über die URL aus. Probieren Sie es selbst: Schreiben Sie den Einzeiler an Stelle des echo $hallo in die eingangs verwendete Beispieldatei global.php. Der Aufruf über das Formular wird weiter funktionieren, mit http://foo.bar/global.php?hello=Oh+ich+Hacker hingegen ist nichts mehr zu machen.

Das Array auslesen

Das Plus an Sicherheit bei der Datenübergabe kostet nur wenig mehr Programmieraufwand. Es gilt, die Daten aus dem Array zu lesen und den Variablen zu übergeben. Dazu gibt es mehrere Ansätze.

Voreweg: Um Programmierern die Umstellung und das Umschreiben ihres Codes zu erleichtern, sind die Arrays von Haus aus global. Sie können also auch ohne explizites global in jeder Funktion eingesetzt werden. Damit will das PHP-Entwicklerteam die Umstellung erleichtern. In vielen Fällen genügt es, die einst Variablen einfach zu ersetzen.

Der einfachste Weg, an die Daten aus dem Array zu kommen ist der direkte, wie diese Zeile zeigt:

echo $_POST["hallo"];

Der Befehl gibt den Inhalt der via POST übergebenen Variablen hallo aus. Das jedoch ist nur in wenigen Fällen sinnvoll. Soll eine Variable im Programm mehrfach genutzt und bearbeitet werden, sollten Sie den Inhalt aus dem Array in die Variable kopieren. Dabei bietet es sich an, bei eventuell fehlenden Variablen einen Default-Wert zu setzen:

if (! ($my_hallo=$_POST["hallo"]))

{

$my_hallo="Defaultwert";

}

echo $my_hallo;

Die if-Anweisung überprüft das Gelingen der Zuweisung von aus dem Array an die Variable. Schlägt dies fehl, sprich, existiert der Schlüssel hallo nicht, erhält $my_hallo einen Default-Wert.

Wie sich hier zeigt, sind die bei der Datenübergabe verwendeten Arrays assoziativ: Im Array sind die übergebenen Variablen als Schlüssel und die zugehörigen Werte als Werte gespeichert liegen. Damit lassen sich beliebige Namen-Werte-Paare an ein Programm übergeben.

Folgendes Code-Beispiel zeigt, wie Sie alle in einem Array übergebenen Werte anzeigen:

<?

echo "Per POST übergebene Variablen:<br>\n";

while (list ($key, $val) = each ($_POST))

{

echo "$key => $val<br>";

}

?>

Die while-Schleife liest den übergebenen Array Eintrag für Eintrag aus. Mit list erhält jeweils die Variable $key den Schlüssel oder Namen des Eintrages und $val dessen Wert. Dieses Verfahren eignet sich nicht unbedingt für den Betrieb auf einer Web-Seite. Aber bei der Fehlersuche ist diese Schleife sinnvoll - sie hilft herauszufinden, ob alle Variablen richtig übergeben sind.

Gekoppelt mit einem Filter allerdings bringt list mehr Leistung. Um bestimmte Einträge aus dem Array heraus zu filtern, wäre ein Weg wie dieser denkbar:

<?

echo "Per POST übergebene Variablen:<br>\n";

while (list ($key, $val) = each ($_POST))

{

switch ($key)

{

case "name":

$name = $val;

break;

 

case "vorname":

$vorname = $val;

break;

 

case "alter":

$alter = $val;

break;

default:

echo "Array-Eintrag $key = $val nicht zulässig<br>\n";

}

}

echo "Die Variablen: \$name: $name, \$vorname: $vorname, \$alter: $alter<br>\n";

?>

Hier nimmt ein Switch-Statement die Wertepaare auseinander. Nur wenn ein bestimmter Eintrag in $key vorhanden ist, wird er in die gleichnamige Variable übernommen. Trifft bei einem Eintrag keiner der Fälle zu, landet das Programm in default: und der Eintrag nebst Inhalt werden als unzulässig gemeldet. Beim Debugging ist dies eine große Hilfe. Ob man aber einem digitalen Einbrecher diese Hilfe in Form der Fehlermeldung zugesteht, sollte wohl überlegt sein.

Ein weiterer sehr einfacher aber unsicherer Weg führt über die Funktion extract. Der folgende Code-Ausschnitt zeigt, wie es geht:

<?

echo "Per POST übergebene Variablen ";

echo "mit extract ausgewertet:<br>\n";

extract ($_POST);

echo "Die Variablen: \$name: $name, \$vorname: $vorname,

\$alter: $alter, \$sonstwas: $sonstwas<br>\n";

?>

extract nimmt die Schlüssel-Wert-Paare und wandelt jeden einzelnen Eintrag in eine Variable mit entsprechendem Wert um. Allerdings entziehen Sie sich selbst der vollen Kontrolle über das Programm. Denn es ist auf diesem Weg wieder möglich, unerwünschte Variablen in das Programm zu schmuggeln.

Als Gegenmittel bietet extract einige Parameter. Mit

extract ($_POST, ENTR_SKIP)

verhindern Sie, dass eine bereits bestehende Variable von der übergebenen überschrieben wird. Das setzt eine saubere Initialisierung der Variablen voraus. Ein anderer Weg wäre, den eingelesenen Variablen erst ein Mal ein Präfix voranzustellen und sie dann auszuwerten. Das geht so:

extract ($_POST, EXTR_PREFIX_ALL, "neu")

Aus einer per POST übergebenen Variable name wird mit diesem Befehl die Variable $neu_name.

Wenn Sie die Programmbeispiele in diesem Abschnitt ausprobieren wollen, hilft wieder ein einfaches Formular. Um eine Fehlermeldung zu provozieren, ist der letzte Formulareintrag namens sonstwas dabei:

<form action="array_switch.php" method="POST">

<input type="text" name="name"></input><br>

<input type="text" name="vorname"></input><br>

<input type="text" name="alter"></input><br>

<input type="text" name="sonstwas"></input><br>

<input type=submit>

</form>

Setzen Sie in action jeweils den Namen des aufzurufenden Programms ein.

Probieren Sie das neue Übergabeverfahren aus. Und verwenden Sie es am besten in allen neuen Projekten. Für geringen Mehraufwand belohnt das neue Verfahren mit deutlich mehr Sicherheit.




Ihr Kommentar:


Name:



Aktualisiert am: 17.05.2015

 

Mehr dazu:

PHP effektiv gegen Hacker-Angriffe absichern

Weiterlesen...