am 5. November 2008
Wie ihr ja wisst, war ich vor kurzem auf der PHP Konferenz und wie jedes Jahr war natürlich auch Sicherheit ein Thema. Stefan Esser ging in seinem Vortrag “Lesser known security problems” auf die Gefahr der Superglobalen $_REQUEST ein. Klar $_GET, $POST und Konsorten sollte man möglichst wenig verwenden, aber man kommt nicht immer daran vorbei. Wenn man sie aber dann doch benutzt, muss man sicherstellen, dass sie auch richtig “entschärft” wird. Ich habe mich mal ein paar Minuten hingesetzt und mir was zu diesem Thema überlegt. Vielleicht gibt es diesen Ansatz schon 100 mal, dann könnt ihr diesen Beitrag getrost überspringen.
Die Erfahrung, die ich gemacht habe ist, dass man sich eine Request Klasse bastelt, die einem $_GET oder $_POST Variablen zurückgibt. Was auch nicht falsch ist, denn so entkoppelt man seinen Code von HTTP. Der Request kann jetzt von irgendwo her kommen. Die meisten Ansätze geben die angefragte Variable aber einfach so zurück, wie sie im Request steht. Jetzt muss der User entscheiden, was er damit macht.
Warum erweitert man die Request Klasse nicht einfach so, dass man dort Filter registrieren kann. Diese Filter würden zum Beispiel bei jeder Variable, die abgefragt wird, die HTML Zeichen escapen. Wenn man einen bestimmten Filter nicht haben möchte, so muss man dies bei der Abfrage explizit abmelden. Ich habe mal angefangen, ein Stück Code zu entwerfen, wie ich mir die Verwendung vorstellen könnte. Ich muss dazu sagen, dass dies hier die einzigen Zeilen Code sind, die ich dazu verfasst habe. Es ist also bis jetzt wirklich nur eine Idee.
<?php
$request = Base_Security_Request::getInstance( );
$request->addSecurityFilter( new Base_Security_HtmlFilter( ) );
$request->addSecurityFilter( new Base_Security_MySqlFilter( ) );
$isReadOnly = $request->getBooleanVariable( 'isReadOnly' );
$userId = $request->getIntegerVariable( 'userId' );
$username = $request->getStringVariable( 'username',
array( Base_Security_RemovedFilter::getName( ) ),
array( Base_Security_AdditionalFilter::getName( ) )
);
$boolVar = $request->getVariable( 'someVar', Base_Security_Datatypes::BOOLEAN );
?>
Wir haben so natürlich den großen Vorteil, dass nur Variablen gefiltert werden müssen, die wir auch tatsächlich verwenden. Und vergessen können wir sicherheitskritische Dinge auch nicht, da es ja automatisch passiert. Braucht man doch eine ungefilterten Variable, so muss man sie explizit anfordern. Da dies nicht so häufig sein sollte, denke ich, dass dies der beste Ansatz ist. Für die Request Klasse habe ich das Singleton Pattern verwendet, da wir nur eine Instanz im ganzen Skript benötigen werden.
Wem die Idee gefällt, der kann gerne mal probieren die Klassen zu schreiben. Ich werde sie auf jeden Fall hier posten. Aber sucht lieber vorher, ob dies nicht schon jedes x-beliebige Framework macht, ich habe es noch nicht nachgeprüft.