Datei auslesen - sicher genug?
Gustav
- php
0 Gustav- menschelei
0 Tom0 Robert Bienert0 Gustav
Hallo,
ich habe einen Newsletter, bei dem die Anhänge nicht per Mail, sondern als Link auf einen Webserver mitgeschickt werden soll, d.h. dass am Ende der Nachricht X Links zu den Anhängen (http://bla.de/Datei) stehen, die sich der Empfänger dann runterladen kann.
Gut, ich könnte es auch per PHP-Klasse anhängen, aber das ganze braucht so schon genug Bandbreite.
(Der Newsletter wird btw nur an Empfänger geschickt die sich freiwillig eingetragen haben :))
Soviel zum Hintergrund.
Da ich die Dateien aber ich einem .htaccess-geschützten Admin-Bereich liegen habe und das auch so bleiben soll, habe ich mir kurz ein Extra-Script gemacht, das mir die Datei ausliest, ein header(Content-disposition) und Co. ausgibt und dann die Datei ausliest und an den Browser schickt - der sie auch wie gewollt verarbeitet, funktioniert also.
Aber: Wenn ja jetzt so ein Witzbold als Dateiname irgendwas.php angibt, kann der sich fröhlich meine Scripte runterladen, und da die Anhänge in /admin/newsletteranhaenge/unixtimestamp_des_sendezeitpunktes/Datei.* liegen, kann er auch ../../index.php oder ../../download.php eingeben und hat dann so - nach ein bisschen Ausprobieren (er weiss ja die Namen der Scripte nicht, aber index etc gibts immer) im schlechtesten fall Zugriff auf den kompletten Rechner bzw. im besten Fall nur Zugriff auf die Dateien, die in meinem Apache-Vhost-Veerzeichnis liegen.
Deshalb habe ich mal einige Sicherheitsprüfungen eingebaut, dass der User wirklich nur Dateien aus dem Verzeichnis /admin/newsletteranhaenge bekommt und keine .htaccess-Dateien, PHP-Scripte und Co. runterladen kann:
<?php
//(...)
//$_GET['id'] ist der Unix-Timestamp, also der Unterordner in dem die Anhänge liegen
//$_GET['datei'] ist der Dateiname.
$location = "admin/newsletteranhaenge/".str_replace("/","",str_replace("\","",str_replace(""","",$_GET['id'])))."/".str_replace("/","",str_replace("\","",str_replace(""","",$_GET['datei'])));
if (substr($location,24,1) == "." OR strtolower(substr($location,-3,3)) == "php" OR OR strtolower(substr($location,-2,2)) == "db" OR strstr($location,".htaccess") OR strstr($location,".htpasswd")) // Sicherheitsprüfung, dass er nich aus dem Ordner rauskommt
die("<H2>Fehler!</H2><BR>\nDieser Anhang wurde nicht gefunden!<BR>\n<BR>Bitte überprüfen Sie den Link!$mess_close");
//(...)
?>
Nun wollte ich eigentlich nur wissen, ob das so reicht, oder ob euch evtl noch was einfällt, wie man das nun umgehen könnte.
Manche Prüfungen sind eigentlich Sinnfrei, denn wenn er keinen Ordner wechseln kann, bekommt er auch keine *.db-Dateien, aber lieber einen zuviel als zu wenig :)
Danke und Gruss - Gustav.
Hallo nochmal,
OR OR
Das is natürlich n copy&paste-Fehler, nur als Anmerkung, hat nichts mit dem PRoblem zu tun :)
Danke und Gruss - Gustav.
Hello,
im Prinzip benötigst Du auch den Umweg über das Script und .htaccess nicht, wenn Du in dem Script nicht die Berechtigung prüfst. Um diese zu prüfen, sendest Du eben einen ausreichend langen Schlüssel zusammen mit dem Schlüssel der Datei. Unter dem Schlüssel der Datei liegt dann der Pfad zur Datei in einer Tabelle und unter der Berechtigung, ob der der User diese Datei lesen darf.
Geht natürlich am besten mit einer Datenbank.
Ohne Script und .htaccess kannst Du die Dateien selber auch unter einem entsprechend langen Schlüssel ablegen, was das Grabben schon genügend schwierig macht. Ist natürlich nicht wirklich sicher. Man könnte immer noch mit Spezialprogrammen 1000 Requests geleichzeitig und das alle 0.08 Sekunden an deinen Webserver absetzen. dann ist der Schlüsselvorrat bei 32^64 Möglichkeiten auch irgendwann aufgebraucht und alle Dateien ausgelesen. Ich habs jetzt nicht ausgerechnet, aber ein paar Tage braucht man da auch, speziell weil ein Apache meistens nur 150 gleichzeitige Requests zulässt.
Harzliche Grüße aus http://www.annerschbarrich.de
Tom
Hallo,
wie meinst du as mit schlüssel?
in eine Datebank eine zufallszahl schreiben und dazu den Pfad und den dann per GET an das Script übermitteln?
Wenn ich das so machen würde wäre ja auch keine Sichereitslücke drin, weil ich ja nur den Dateien IDs gebe, die zum runterladen gedacht sind?
Danke und Gruss - Gustav.
Hello,
wie meinst du as mit schlüssel?
in eine Datebank eine zufallszahl schreiben und dazu den Pfad und den dann per GET an das Script übermitteln?Wenn ich das so machen würde wäre ja auch keine Sichereitslücke drin, weil ich ja nur den Dateien IDs gebe, die zum runterladen gedacht sind?
Genau. Weil Du dann eine "Translation" eingebaut hast. Die lässt nur vorhandene Begriffe zu.
Pfade sollte man niemals direkt weiterleiten. Man kann zwar mittels basename(), realpath(), pathinfo(), usw. schon eine Menge machen, aber wohl ist mir dabei auch immer nicht.
Harzliche Grüße aus http://www.annerschbarrich.de
Tom
Hallo,
Moin!
ich habe einen Newsletter, bei dem die Anhänge nicht per Mail, sondern als Link auf einen Webserver mitgeschickt werden soll, d.h. dass am Ende der Nachricht X Links zu den Anhängen (http://bla.de/Datei) stehen, die sich der Empfänger dann runterladen kann.
Sehr interessante Sache, damit kommt man Leuten mit schwacher Internetanbindung sehr entgegen. Ich finde sowas nicht schlecht.
Gut, ich könnte es auch per PHP-Klasse anhängen, aber das ganze braucht so schon genug Bandbreite.
Das verstehe ich jetzt nicht. Meinst du damit einfach, dass du die Anhänge auch an die Mail anhängen könntest?
Da ich die Dateien aber ich einem .htaccess-geschützten Admin-Bereich liegen habe und das auch so bleiben soll, habe ich mir kurz ein Extra-Script gemacht, das mir die Datei ausliest, ein header(Content-disposition) und Co. ausgibt und dann die Datei ausliest und an den Browser schickt - der sie auch wie gewollt verarbeitet, funktioniert also.
Du schreibst, die Datei liegt in einem Admin-Bereich? Doch wohl hoffentlich nicht in _dem_ Admin-Bereich, das soll wohl heißen, dass die Anhänge in einem separaten Verzeichnis liegen.
Aber: Wenn ja jetzt so ein Witzbold als Dateiname irgendwas.php angibt, kann der sich fröhlich meine Scripte runterladen, und da die Anhänge in /admin/newsletteranhaenge/unixtimestamp_des_sendezeitpunktes/Datei.* liegen, kann er auch ../../index.php oder ../../download.php eingeben und hat dann so - nach ein bisschen Ausprobieren (er weiss ja die Namen der Scripte nicht, aber index etc gibts immer) im schlechtesten fall Zugriff auf den kompletten Rechner bzw. im besten Fall nur Zugriff auf die Dateien, die in meinem Apache-Vhost-Veerzeichnis liegen.
Nein, der Witzbold (welche Adresse hat dein Server nochmal >:->) kann damit die komplette Verzeichnisstruktur auf diesem Server herausbekommen und sich alle Dateien anzeigen lassen, zu denen der Apache-Prozess die Leseberechtigung hat. Ich persönlich würde bei so einem Script z.B. gleich erstmal gib_mir_die_datei.php?datei=/etc/passwd ausprobieren.
Deshalb habe ich mal einige Sicherheitsprüfungen eingebaut, dass der User wirklich nur Dateien aus dem Verzeichnis /admin/newsletteranhaenge bekommt und keine .htaccess-Dateien, PHP-Scripte und Co. runterladen kann:
Sehr weise Entscheidung. Aber wie wärs es denn damit: .htaccess erlaubt es dir, AFAIK den Zugriff auf bestimmte Dateien zu verbieten, damit bräuchtest du kein spezielles Script und Auto-Indexing kannst du damit auch abschalten. Abgesehen davon, dass der Apache evtl. die Dateien performanter ausliefert als dein PHP-Script es kann.
Ein ganz schöner Wust ist dass:
$location = "admin/newsletteranhaenge/" . str_replace("/","", str_replace("\","", str_replace(""","",$_GET['id']))) . "/" . str_replace("/","", str_replace("\","", str_replace(""","",$_GET['datei'])));
if (substr($location,24,1) == "." OR strtolower(substr($location,-3,3)) == "php" OR strtolower(substr($location,-2,2)) == "db" OR strstr($location,".htaccess") OR strstr($location,".htpasswd")) // Sicherheitsprüfung, dass er nich aus dem Ordner rauskommt
die("<H2>Fehler!</H2><BR>\nDieser Anhang wurde nicht gefunden!<BR>\n<BR>Bitte überprüfen Sie den Link!$mess_close");//(...)
?>
Sieht bisher ganz gut aus, nur glaube ich, dass du evtl. zu viel machst. Eigentlich müsste es reichen, Dateien, die mit '/' oder '.' anfangen zu ignorieren, außerdem würde ich aufpassen, ob zufällig "\0" im Dateinamen vorkommt, d.h. ob der QUERY_STRING %00 enthält.
Um die Sache mit den PHP-Dateien zu erschlagen, verweigere den Zugriff auf Dateien, die mit .php enden oder umgekehrt, prüfe gegen eine Attachment-Whitelist.
Keine Ursache, Robert
Guten Abend,
Gut, ich könnte es auch per PHP-Klasse anhängen, aber das ganze braucht so schon genug Bandbreite.
Das verstehe ich jetzt nicht. Meinst du damit einfach, dass du die Anhänge auch an die Mail anhängen könntest?
ja.
aber da eben nicht jeder ne 50Mbit-LEitung vom Rechenzentrum um die Ecke hat... und mich der Traffic beim senden auch teuer kommt mach ichs eben so ;)
Da ich die Dateien aber ich einem .htaccess-geschützten Admin-Bereich liegen habe und das auch so bleiben soll, habe ich mir kurz ein Extra-Script gemacht, das mir die Datei ausliest, ein header(Content-disposition) und Co. ausgibt und dann die Datei ausliest und an den Browser schickt - der sie auch wie gewollt verarbeitet, funktioniert also.
Du schreibst, die Datei liegt in einem Admin-Bereich? Doch wohl hoffentlich nicht in _dem_ Admin-Bereich, das soll wohl heißen, dass die Anhänge in einem separaten Verzeichnis liegen.
Adminbereich ist auf /admin
Anhänge in /admin/anhänge
Aber: Wenn ja jetzt so ein Witzbold als Dateiname irgendwas.php angibt, kann der sich fröhlich meine Scripte runterladen, und da die Anhänge in /admin/newsletteranhaenge/unixtimestamp_des_sendezeitpunktes/Datei.* liegen, kann er auch ../../index.php oder ../../download.php eingeben und hat dann so - nach ein bisschen Ausprobieren (er weiss ja die Namen der Scripte nicht, aber index etc gibts immer) im schlechtesten fall Zugriff auf den kompletten Rechner bzw. im besten Fall nur Zugriff auf die Dateien, die in meinem Apache-Vhost-Veerzeichnis liegen.
Nein, der Witzbold (welche Adresse hat dein Server nochmal >:->) kann damit die komplette Verzeichnisstruktur auf diesem Server herausbekommen und sich alle Dateien anzeigen lassen, zu denen der Apache-Prozess die Leseberechtigung hat. Ich persönlich würde bei so einem Script z.B. gleich erstmal gib_mir_die_datei.php?datei=/etc/passwd ausprobieren.
tja. und da / nicht geht haste pech gehabt.
wie willst du damit alle datein auslesen?
Deshalb habe ich mal einige Sicherheitsprüfungen eingebaut, dass der User wirklich nur Dateien aus dem Verzeichnis /admin/newsletteranhaenge bekommt und keine .htaccess-Dateien, PHP-Scripte und Co. runterladen kann:
Sehr weise Entscheidung. Aber wie wärs es denn damit: .htaccess erlaubt es dir, AFAIK den Zugriff auf bestimmte Dateien zu verbieten, damit bräuchtest du kein spezielles Script und Auto-Indexing kannst du damit auch abschalten. Abgesehen davon, dass der Apache evtl. die Dateien performanter ausliefert als dein PHP-Script es kann.
Ein ganz schöner Wust ist dass:
$location = "admin/newsletteranhaenge/" . str_replace("/","", str_replace("\","", str_replace(""","",$_GET['id']))) . "/" . str_replace("/","", str_replace("\","", str_replace(""","",$_GET['datei'])));
if (substr($location,24,1) == "." OR strtolower(substr($location,-3,3)) == "php" OR strtolower(substr($location,-2,2)) == "db" OR strstr($location,".htaccess") OR strstr($location,".htpasswd")) // Sicherheitsprüfung, dass er nich aus dem Ordner rauskommt
die("<H2>Fehler!</H2><BR>\nDieser Anhang wurde nicht gefunden!<BR>\n<BR>Bitte überprüfen Sie den Link!$mess_close");//(...)
?>Sieht bisher ganz gut aus, nur glaube ich, dass du evtl. zu viel machst. Eigentlich müsste es reichen, Dateien, die mit '/' oder '.' anfangen zu ignorieren, außerdem würde ich aufpassen, ob zufällig "\0" im Dateinamen vorkommt, d.h. ob der QUERY_STRING %00 enthält.
Um die Sache mit den PHP-Dateien zu erschlagen, verweigere den Zugriff auf Dateien, die mit .php enden oder umgekehrt, prüfe gegen eine Attachment-Whitelist.
Hm, dass mit der Whitelist ist eine gute Idee, und dass es zu viele Prüfungen sind habe ich ja geschrieben :)
Aber trotzdem - lieber zu sicher als zu unsicher :)
Keine Ursache, Robert
Gruss und danke, Gustav
Kleiner Nachtrag:
Ich habe noch eine interessante Sicherheitslücke vergessen: Wenn ich dem Attachment-Script als Parameter einen Pfad angebe, der '..' enthält, komme ich damit ebenfalls aus dem aktuellen Verzeichnis heraus nach oben. Ich denke, mit einem Alias auf Apache-Ebene kämst du relativ sicher davon, d.h. die Anhänge liegen einfach irgendwo anders und per Alias packst du die Dinger unter /news-letter-anhaenge/ oder so. Dann braucht du kein (potenziell unsicheres) PHP-Script dafür und irgendwelche Pfade zu prüfen, dann macht nämlich der Apache die Arbeit für dich.
Frohe Ostern, Robert