Kontakt aufnehmen

Sicherheit des Include-Befehls – Code & Blog

Code & Blog Logo

Code & Blog Logo

Im letztem Artikel von Code & Blog haben wir per Include bereits die ersten Seiten importiert. Doch dieses System ist noch nicht wirklich sicher. Man könnte dadurch fremde PHP-Skripte, oder Daten vom Server, die der User nicht umbedingt sehen sollte anzeigen. Das geht zum Beispiel so:

index.php?include=http://böseseite/serverkill.php

oder wenn wir zum Beispiel Daten von unseren Server nehmen, könnte man hiermit schon unsere settings.test.php auslesen:

http://cms.stevieswebsite.de/index.php?include=../../system/settings.test.php

So kann es natürlich nicht sein. Also habe ich mit Hilfe von Christian Land (tagdocs.de), der mich darauf aufmerksam gemacht hat, eine Funktion geschrieben, welche dieses abfiltert. Diese Funktion steht in der Datei filterfilename.php im Verzeichnis system:

<?PHP
function filterfilename($filename){
    $filename = strtolower($filename);
    $filename = preg_replace("/[^a-z0-9-/]/i","",$filename);
    if($filename[0] == "/"){
        $filename = substr($filename,1);
    }
    $filename .= ".php";
    if(!file_exists($filename)){
        $filename = "content/articles/errors/404.php";
    }
    return $filename;
}
?>

Als Parameter wird die Seite angegeben, die überprüft werden soll. Als erstes wird der Dateiname mit strtolower in Kleinbuchstaben gepackt, da in unseren CMS Groß- und Kleinschreibung in der Urlegal ist. Danach werden mit preg_replace und einem regulären Ausdruck alle Zeichen, die keine Kleinbuchstaben, Zahlen, Bindestriche oder Slashes sind entfernt. Dabei werden jedoch auch alle „.“ entfernt, wobei wird beim Parameter kein „.php“ o.Ä. angeben können. Das machen wir aber in einen späteren Artikel und Mod Rewrite wieder rein.

Nun wird nachgesehen, ob das erste Zeichen ein „/“ ist und wenn ja wird es entfernt. Dies ist dazu da, um nicht absolute Pfade (von Linux) anzunehmen.

Da wir ja jetzt keine Dateiendung haben, müssen wir natürlich das „.php“ nochmal dranhängen.

Jetzt noch einmal prüfen, ob die Datei existiert. Wenn sie das nicht tut, wird eine Fehlerseite geladen, welche wir später noch erstellen werden.

Als letztes wird mit return der neue Dateiname zurückgegeben.

In unserer index.php hat sich natürlich nun der Aufruf geändert. Er sieht nun so aus:

<?PHP
include("system/filterfilename.php");
include(filterfilename("content/articles/".$_GET['include']));
?>

Verwandte Themen

Dies ist ein Beitrag aus der Aktion Code & Blog, in der hier ein eigenes CMS erstellt wird.

Du arbeitest in einer Agentur oder als Freelancer?
Dann wirf doch mal einen Blick auf unsere Software FeatValue.

Kommentare

Akini schrieb am 28.10.2009:

Hi, eine Frage wieso öffnet die index.php jetzt nicht mehr die testseite.php mit include?? mfg Akini

Stefan Wienströer schrieb am 29.10.2009:

Dies geschieht mitterweile in der Klasse sys in der Methdoe includeContent. Diese Methode wird immer im jeweiligen Skin aufgerufen, damit es völlig flexibel ist.

Sirblacksoul schrieb am 08.06.2010:

Erster Absatz: fremde PHP-Scripte, oder Daten vom Server, die der User nicht umbeding -----&gt; fremde <b>PHP-Skripte</b>(Deutsch-Englisch :D), oder Daten vom Server, die der User nicht <b>umbedingt</b>

Fremd schrieb am 29.06.2010:

Bei mir wird angezeigt das der $end Syntax falsch ist (Absatz 13): Parse error: syntax error, unexpected $end in D:xampphtdocsCMSsystemfilterfilename.php on line 13

Stefan Wienströer schrieb am 30.06.2010:

Kannst du mal die Datei /system/filterfilename.php mit dieser ersetzen: http://code.google.com/p/contentlion/source/browse/trunk/system/filterfilename.php

Steffen schrieb am 19.07.2010:

Bei mir schmeist's jetzt 'Objekt nicht gefunden!' aus. Wie rufe ich denn jetzt testseite.php aus?

Steffen schrieb am 19.07.2010:

Also bei mir wird immer false ausgegeben. Als ob die datei testseite nicht existiert.

Stefan Wienströer schrieb am 20.07.2010:

Hi, erstmal willkommen im Tutorial ;-) Kannst du mal am Anfang der Funktion mit echo den $filename ausgeben und dann hier posten, was dort steht?

BaBa schrieb am 04.08.2010:

Warning: include(system/filterfilename.php) [function.include]: failed to open stream: No such file or directory in C:xampphtdocssystemindex.php on line 2 Warning: include() [function.include]: Failed opening 'system/filterfilename.php' for inclusion (include_path='.;C:xamppphpPEAR') in C:xampphtdocssystemindex.php on line 2 Fatal error: Call to undefined function filterfilename() in C:xampphtdocssystemindex.php on line 3 das kommt bei mir.. habe alles schritt für schritt nachgebaut, und ab hier geht es nicht mehr..

Stefan Wienströer schrieb am 04.08.2010:

Liegt die filterfilename.php im Ordner system?

BaBa schrieb am 04.08.2010:

ja, liegt sie

Stefan Wienströer schrieb am 04.08.2010:

kannst du mir mal die aktuelle /index.php per Mail schicken? Adresse steht im Impressum.

HTP schrieb am 08.09.2010:

Erstmal vielen Dank für das Tutorial, womit sich PHP- und MySQL-Kenntnisse klasse erweitern lassen. Bin, wie man sieht bisher nicht sehr weit, aber es ist sehr hilfreich und verständlich. Nun zu meiner Frage (Achtung bin Anfänger;) ): Wäre es sinnvoll, an geeigneter Stelle nach der file_exists() eine clearstatcache() zu machen, damit der Zwischenspeicher "sauber" gehalten wird? Oder wird das Ergebnis nachher noch benötigt? Vielen Dank für die Hilfe!

Stefan Wienströer schrieb am 08.09.2010:

werd ich mir mal ansehen

Methi-jr schrieb am 14.09.2010:

Erstes Hinderniss ^^ Im Artikel 8 wurde ohne Sicherheitsaufwand die testseite.php abgefragt und wiedergegeben! Hier mit Sicherheitsaufwand sollte er diese doch auch wiedergeben oder? Bei mir sagt er dauernd das die 404.php fehlt (und erstell ich eine, wird diese ausgegeben!)

Methi-jr schrieb am 14.09.2010:

okay habs ... hab die filterfilename.php durch die andere hocgeladene ersetzt (wo is da der Unterschied und warum wurde nicht weiter drauf eingegangen?) und der aufruf im Browser muss nu natürlich ohne .php erscheinen! http://www.meinserver/blabla/index.php?include=testseite

Dirk schrieb am 11.02.2011:

Hi Stefan, bei mir funktionieren beide Funktionen fast gleich. Mit dem einen Unterschied, dass, wenn ich .php noch anfüge, bei der alten Funktion eine Fehlermeldung kommt und bei der neuen keine. Und bei beiden wird "content/articles/testseite.php" angezeigt, wenn ich "echo $filename;" eingebe. Welche ist besser? Vielen Dank Dirk

Stefan Wienströer schrieb am 11.02.2011:

Neu ist immer gut ;-)

Michael schrieb am 21.02.2011:

Hallo, also entweder Blick ich da was grundsätzliches nicht oder in der Funktion ist ein Fehler drin. Wenn man einfach mal echo $filename .= ".php"; in die Funktion eingibt, erhält man als Ergebnis z.b: sowas in der Art: http//localhost/eine seite/indexphp.php Der usprüngliche Punkt vor dem ersten php wurde also entfernt und hinten ein Punkt und php ran gehängt. also so wirds bei mir jedenfalls angezeigt. Des kann doch nicht richtig sein so? Mache ich dann sowas--&gt; $filename = preg_replace("/[^a-z0-9-./]/i","",$filename); und streiche die Zeile $filename .= ".php"; ersatzlos. dann stimmts wieder mit der Anzeige. Oder hab ich da einen kompletten Denkwurm irgendwo? Lg Michael

Jog schrieb am 21.06.2011:

Das sehe ich genauso es wird nur der Punkt von .php entfernt und nicht die letzten 3 Buchstaben mit. Oder gibt es schon eine neue Version des Artikels? Gruß

Stefan Wienströer schrieb am 21.06.2011:

Hi, eine aktuealisierte Version des Artikels wird es nicht geben, da es im aktuellen Stand funktioniert. Zu diesem Zeitpunkt müssen Seiten noch so aufgerufen werden: /localhost/index.php?include=seite Den aktuellen Quellcode findet ihr übrigend hier: http://svn.contentlion.org/listing.php?repname=contentlion-core&

Canna schrieb am 31.07.2011:

Hey, Erstmal Danke das du für ein CMS ein Tutorial erstellst! Nun habe ich aber folgendes problem.. die index.php zeigt mir immer den Fehler an! Fatal error: Call to undefined function filterfilename() in D:xampphtdocscmsindex.php on line 3

Stefan Wienströer schrieb am 31.07.2011:

Hi, existiert bei dir die Datei /system/classes/filterfilename?

Canna schrieb am 31.07.2011:

ja naklar ;) ----------- Aber mal was anderes..Kann ich das CMS iwo direkt mit allen Dateien runterladen? lg

Stefan Wienströer schrieb am 31.07.2011:

Hi, dann schau mal nach was darin steht. Und ist die Datei in der index.php importiert? Den aktuellen Download bekommst du unter https://www.contentlion.de

Canna schrieb am 31.07.2011:

Ach..Egal jetzt..i bekomme das ne hin ein eigenes cms zu schreiben er spuckt mir andauernd fehler aus -.-' Selbst bei CL..

Biene schrieb am 06.10.2011:

Hi ich bin es mal wieder... nur eine Frage ;) muss man hier nicht Testseite.php noch eintragen? include(filterfilename("content/articles/(Testseite.php) ".$_GET['include']));

Stefan Wienströer schrieb am 07.10.2011:

ne, das steht ja im $_GET['include'] ;-)

Cedric schrieb am 04.11.2011:

Hallo, da ich mit diesem Tut. doch so einige Schwierigkeiten habe, möchte ich euch bitten mir ein Download des fertigen CMS zugeben. So das ich die einzelnen Schritte besser nachvollziehen kann. Sonst müsste ich hier mit diesem Tutoriell aufhören. Grüsse Cedric

Stefan Wienströer schrieb am 04.11.2011:

Das CMS kannst du über https://www.contentlion.de herunterladen.

Todoer schrieb am 15.11.2011:

Vorweg: Vielen Dank für dieses Tutorial. So komme ich endlich mal dazu mich sinnvoll mit der Materie php und MySQL auseinander zusetzten! Mir fällt jedoch auf das in dem Quellcode zu "filterfilename" oben im Article noch die Überprüfung per "file_exists" eingebunden ist. Wohingegen in der anderen (neuen?) fassung aus deinem Kommentar/trunk dies nicht drin ist und im prinzip nur geprüft wird ob eine datei innerhalb von "content/articles" angegeben wurde. Ist es also einfach nur durch die neue überprüfung gar nicht mehr nötig das ganze auch per "file_exists" zu prüfen?

Todoer schrieb am 15.11.2011:

Das Verzeichnis "errors" wurde im vorher gegangen Artikel "http://blog.stevieswebsite.de/2009/04/dateisystem-des-cms-code-blog/" (Dateistruktur) nicht mit erstellt... daher kommt es in beiden Versionen der filterfilename unter Umständen zu einer Fehlermeldung an dieser stelle.

Stefan Wienströer schrieb am 15.11.2011:

In der aktuellen Version ist die Struktur anders, die Artikel sind alle in der DB gespeichert. Zum error-Verzeichnis: Ahh^^ Dann erstell das mal ;-)

Tim Lehming schrieb am 24.11.2011:

Hallo, eine weitere Variante wäre htmlspecialchars(). Diese Methode ist auch nicht ganz so kompliziert und Funktioniert gegen jede art von Cross Site Scripting. Es werden dann Zeichenreferenzen Verwendet. Diese sehen dann z.B. so aus: &quot; Grüße Tim Lehming

Tim Lehming schrieb am 24.11.2011:

Nachtrag: &amp;qout; Es wurde natürlich als " angezeigt.

Über uns

Stefan Wienströer

Wir entwickeln Webanwendungen mit viel Leidenschaft. Unser Wissen geben wir dabei gerne weiter. Mehr über a coding project

Cookie-Einstellungen

Helfen Sie dabei, uns noch besser zu machen. Wir nutzen Cookies und ähnliche Technologien, um die Website auf Ihre Bedürfnisse anzupassen. Zur Datenschutzerklärung

Auswahl speichern