Warnung: file_put_contents(/home/www/web1/html/php_dev/test.txt) [function.file-put-contents]: failed to open stream: Permission denied in /home/www/web1/html/php_dev/sys/lib.activity.php (Zeile 58)
Download via header attachment... [Archiv] - PHP-Scripte PHP-Tutorials PHP-Jobs und vieles mehr
ebiz-webhosting
- Ad -
php-resource




Archiv verlassen und diese Seite im Standarddesign anzeigen :
Download via header attachment...


 
nichtsooft
21-09-2006, 07:42 
 
Hi Leute!

Hab ein problem mit nem downloadscript! Natürlich hab ich auch schon rumgesucht und bin dabei hierrauf (http://www.php-resource.de/forum/showthread.php?s=&threadid=75749&highlight=Download) gestoßen. Jedoch konnte mir dieser Threat leider auch nicht weiter helfen! :(

Mein aktuelles Script sieht so aus:
Link = download.php?file=../pics/galerie/Computer/mouselack/IMG_0358.JPG
<?php
$datei = $_GET[file];
header("Expires: 0");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Content-Type: application/force-download");
header("Content-Description: File Transfer");
header("Content-Disposition: attachment; filename=$datei");
header("Content-Transfer-Encoding: binary");
readfile($datei);
?>

Problembeschreibung:
Der Download-Dialog erscheint wie geplant, ABER:
Alle Slashes werden durch Minus-Zeichen ersetzt! Bsp:
..-pics-galerie-Computer-mouselack-IMG_0358.JPG

urlencode &Co. waren irgendwie nutzlos!

Danke für eure Hilfe!

 
Trashar
21-09-2006, 07:46 
 
das ist normal..

aber davon mal abgesehen.
Dir ist klar das du damit eine extrem große sicherheitslücke öffnest ja??

download.php?file=../../config.php oder so
und zack kann man sishc schön die daten runterladen die man bruahct..

da du es also anders lösen solltest braucht man auf deine anderes problem nicht weiter eingehen..

 
nichtsooft
21-09-2006, 07:52 
 
Original geschrieben von Trashar
...da du es also anders lösen solltest braucht man auf deine anderes problem nicht weiter eingehen..

Hast du eventuell nen Lösungsansatz oder wenigstens ein "Stichwort" für mich parat!?

 
Trashar
21-09-2006, 07:57 
 
header("Content-Disposition: attachment; filename=$datei");


und in $datei steht sowas wie ../../ordner/foobar/blub.jpg

Und der wandelt die / automatisch in - um
Da kannst dich quer stellen das wird sich nich ändern

so und nun änder dein download script..

 
nichtsooft
21-09-2006, 07:59 
 
Sehr hilfreich und vor allem freundlich Trash!

Hat jemand nen besseren Lösungsansatz als mein problem zu zitieren?

Danke nochmals!

 
Trashar
21-09-2006, 08:00 
 
Da kannst dich quer stellen das wird sich nich ändern

DA STEHT DAS ES NICHT ÄNDERBAR IST!

Was du machen könntest, $datei aufzusplitten..

Suche nach dem letzten / und den rest darein schreiben.. dann hast du nur den Dateinamen..

 
nichtsooft
21-09-2006, 08:05 
 
Man Trash!?

Das es nicht änderbar ist ist kein Lösungsansatz!

Ich versuche nen download-link zu bauen und bin aufm Holzweg; Das hab ich schon eingesehn als ich mich entschieden hab das Problem hier zu posten!
Um ehrlich zu sein ich denke leute die ihre eigenen Foren coden haben sicher nen besseren Tipp als "...da kannst du dich quer legen...", oder? ;)

Back to Topic: Das mit dem aufsplitten geht leider nicht, da der Pfad sich andauernd ändert! =(

Würde ne Verschlüsselung was bringen? MD5 oder so?

 
Trashar
21-09-2006, 08:21 
 
na und dann splitte pfad unabhängig auf.. suche nach dem letzten / (strrpos glaub ich war das) und gib den rest aus..
Da ist es scheiß egal wie der pfad ist..

Du willst einen lösungsansatz? Tja danns chau in den php code.. oder vielleicht gleich in den apachen code.. irgendwo muss ja so ein header teil drin sein, der die / in - ändert
da würd ich ansetzen..
Ist das nun ein Lösungsansatz?

Md5 ist keine verschlüsselung, es ist eine Hash Funktion

 
wahsaga
21-09-2006, 09:06 
 
Original geschrieben von nichtsooft
Ich versuche nen download-link zu bauen und bin aufm Holzweg; Das hab ich schon eingesehn als ich mich entschieden hab das Problem hier zu posten!
Und du willst behaupten, dass alle anderen Threads hier zum Thema auch nur auf Holzwege führen?
Das mit dem aufsplitten geht leider nicht, da der Pfad sich andauernd ändert! =(
Aua.

Falls es dir noch nicht bekannt sein sollte: Man kann in PHP nicht nur mit Festwerten arbeiten, sondern auch mit so tollen Dingern, die sich "Variablen" nennen. Und deren Inhalt kann man auch bearbeiten, es gibt beispielsweise Stringfunktionen, etc.


Sorry für den Sarkasmus, aber du stellst dich extrem ... an.

 
nichtsooft
21-09-2006, 15:42 
 
Ohhh? Es gibt tatsächlich Variablen in PHP? :eek:

Bin mir sicher die kann ich auch noch von Datei zu Datei zaubern, was!?

Ne; Mal wieder ernst...:
Ich code ne Galery in einfachster Form! Ein Verzeichnis wird gelesen und die darin enthaltenen Bilder als thumbs angezeigt. Diese Bilder sind nicht in ner DB erfasst, also kann ich nicht mit IDs (Bsp.: download.php?imgid=225568) arbeiten.
Ich muss irgendwie den ganzen Dateipfad, bzw. die Variable die den Dateipfad beschreibt an die "download.php" senden und dafür gibt's meines Erachtens nach nur 3 Wege. Cookie, POST und GET (wovon ich aber situationsbedingt nur letzeres verwenden kann).

Soweit richtig?

 
wahsaga
21-09-2006, 16:07 
 
Original geschrieben von nichtsooft
Ich muss irgendwie den ganzen Dateipfad, bzw. die Variable die den Dateipfad beschreibt an die "download.php" senden und dafür gibt's meines Erachtens nach nur 3 Wege. Cookie, POST und GET (wovon ich aber situationsbedingt nur letzeres verwenden kann).
Ja.
Und?

 
nichtsooft
21-09-2006, 16:19 
 
ok; weiter...

wenn ich eine, den Dateipfad beschreibende Variable per URL mitschicke, sieht das wiederum so aus:
download.php?datei=pics/galerie/bla/bla/blub.jpg

Das ist allerdings wie schon Trash gemeint hat extrem unsicher.
Jetzt könnte ich die Sache wie schon erwähnt aufsplitten, so dass die URL dann so aussieht:
download.php?sub1=bla&sub2=bla&file=blub.jpg*

Wobei ich aber hier nach wie vor ein Sicherheitsleck offen lasse.


*= (pics/galerie) bleibt konstant.

 
wahsaga
21-09-2006, 16:24 
 
Original geschrieben von nichtsooft
wenn ich eine, den Dateipfad beschreibende Variable per URL mitschicke, sieht das wiederum so aus:
download.php?datei=pics/galerie/bla/bla/blub.jpg
Sowas machst du doch hoffentlich nicht - ohne die Daten URL-gerecht zu kodieren?
Wobei ich aber hier nach wie vor ein Sicherheitsleck offen lasse.
Überpüfe, ob der angegebene Pfad "erlaubt" ist.

 
TobiaZ
21-09-2006, 16:34 
 
Na klar. die zweite Variante macht das ganze kein Stück sicherer, nur ein wenig unscheinbarer.

Aber du kennst das Problem. Nun überlege was getan werden muss, damit die Manipulation nicht stattfinden kann. Dabei geht es in erster Linie noch nichteinmal um konkreten PHP-Code, sondern erstmal nur um den Grundgedanken. Wenn du den verstanden hast, kannst du auch entsprechend vorgehen.

 
kuddeldaddeldu
21-09-2006, 16:37 
 
Hi,

1. zur Sicherheitslücke:

Und warum überprüfst Du nicht einfach vorher mal die GET-Variable, ob
der übergebene Pfad auch zulässig ist?

2. Dateiname:

Es kann doch nicht so schwer sein, aus einem Pfad den Dateinamen zu
lesen. In der Header-Zeile brauchst Du doch nur den, bzw. gehört da
kein Pfad rein. Was Du dort angibst, ist wie ein "Speichern unter..." -
Namensvorschlag für die Datei.

 
nichtsooft
21-09-2006, 16:40 
 
Edit:
Original geschrieben von kuddeldaddeldu
...Es kann doch nicht so schwer sein, aus einem Pfad den Dateinamen zu lesen...
Ist es auch nicht! -> basename(). Aber ich durchschau nicht was du mir damit sagen willst? Wenn ich nur den Dateinamen ohne Pfad angebe, wird selbst PHP die Datei nicht finden!


Zur Codierung/Decodierung:
Nun ja; ich hab an und für sich mit htmlentities() und html_entity_decode() rumexperimentiert um das ganze URLgerecht zu machen.

Zur Überprüfung ob ein Pfad erlaubt ist:
Es sind grundsätzlich alle Dateien erlaubt, die im Verzeichniss "pics/galerie" abgelegt sind. d.h. wenn ich diesen String vor jede emfangene URL hänge kann der User eigentlich bloss noch erlaubte Dateien erreichen.

Punch me if I'm wrong!

 
TobiaZ
21-09-2006, 16:43 
 
NEIN.

Ein einfaches ../ reicht, um eine ebene Höher zu kommen. Das "Startverzeichnis"-setzen ist also keine Wirksame absicherung.

 
jahlives
21-09-2006, 16:54 
 
@topicstarter
Dateiname:

echo basename('irgendEinLanger/und/komplizierter/pfad/index.html');


Nun ja; ich hab an und für sich mit htmlentities() und html_entity_decode() rumexperimentiert um das ganze URLgerecht zu machen.

Würde ich jetzt urldecode() und urlencode() dazu verwenden...

wenn ich diesen String vor jede emfangene URL hänge kann der User eigentlich bloss noch erlaubte Dateien erreichen.


if(file_exists($_SERVER['DOCUMENT_ROOT'].'/pics/gallery/'.basename($_GET['datei']))){
//Datei ist im erlaubten Verzeichnis
}else{
die('Diese Datei darf nicht runtergeladen werden. Und Tschüss');
}

Dann darfst du als Datei aber nur noch den Namen übergeben und nicht mehr den gesamten Pfad.
basename($_GET['datei']) sollte imho dafür sorgen dass nur der Dateiname verwendet wird und allfällige Pfadanhängsel abgeschnitten werden.

Gruss

tobi

 
kuddeldaddeldu
21-09-2006, 17:04 
 
Hi,

Aber ich durchschau nicht was du mir damit sagen willst? Wenn ich nur den Dateinamen ohne Pfad angebe, wird selbst PHP die Datei nicht finden!

Wenn ich Dich richtig verstanden habe, geht das Download-Fenster auf
und Du kannst die Datei abspeichern, blöd ist nur, dass er da so'n
komischen Namen vorschlägt?

Nun ja; ich hab an und für sich mit htmlentities() und html_entity_decode() rumexperimentiert um das ganze URLgerecht zu machen.

Dafür eignen sich eher URL-Funktionen.

Es sind grundsätzlich alle Dateien erlaubt, die im Verzeichniss "pics/galerie" abgelegt sind. d.h. wenn ich diesen String vor jede emfangene URL hänge kann der User eigentlich bloss noch erlaubte Dateien erreichen.

Wenn dieses Verzeichnis feststeht, warum übergibst Du dann
überhaupt Pfade? Dann übergib doch gleich nur die Namen und
bastel Dir für Dein readfile den Pfad davor. Hierbei trotzdem nicht
vergessen, den Namen zu überprüfen, s. Tobiaz!

Punch me if I'm wrong!

PATSCH!!! :D

 
nichtsooft
21-09-2006, 17:05 
 
@ jahlives

Von der Idee her garnicht schlecht!

if(file_exists($_SERVER['DOCUMENT_ROOT'].'/pics/gallery/'.basename($_GET['datei']))){
//Datei ist im erlaubten Verzeichnis
}else{
die('Diese Datei darf nicht runtergeladen werden. Und Tschüss');
}

Aber was wenn die Datei in einem Subverzeichniss liegt? Bsp:
/pics/gallery/bla/bla/blub/bild.jpg

 
3DMax
21-09-2006, 17:11 
 
Original geschrieben von nichtsooft
Aber was wenn die Datei in einem Subverzeichniss liegt? Bsp:
/pics/gallery/bla/bla/blub/bild.jpg [/B]
dann kannst du ja mit realpath() den kompletten pfad bilden und dann überprüfen, ob er mit /pics/gallery beginnt.

 
nichtsooft
22-09-2006, 11:36 
 
NÖ Leute ich steig da absolut nicht durch! Sitze jetzt länger als nen Tag dahinter und schaff's nicht! Bin müde und geh jetzt schlafen!

Jmd ne idee ob man sowas als snippet irgendwo im web bekommt?

 
kuddeldaddeldu
22-09-2006, 15:50 
 
Hi,
Jmd ne idee ob man sowas als snippet irgendwo im web bekommt?
Nö.

Das halte ich aber auch nicht für nötig. Du bist doch eigentlich fast am
Ziel. Wenn Du Hilfe willst, musst Du uns aber genau sagen, womit Du
nicht klarkommst. Hast Du ein Problem mit der Überprüfung des
Verzeichnisses? Wenn ja welches? Mach Testausgaben Deiner
Variablen.
Stört Dich der komische Dateiname? Setze in der entsprechenden
Header-Zeile (Content-Disposition...) filename auf den Dateinamen,
nicht auf den Pfad (ich fände es übrigens EAB, wenn mir als Download-
Name ein Pfad vorgeschlagen wird. Der wird auf meinem Rechner
selten existieren, und wenn, will ich das da aber vielleicht gar nicht rein haben).

NÖ Leute ich steig da absolut nicht durch! Sitze jetzt länger als nen Tag dahinter und schaff's nicht! Bin müde und geh jetzt schlafen!

Guts Nächtle ;)

 
nichtsooft
22-09-2006, 18:17 
 
Nunja; womit ich nicht klar gekommen bin und was ich selbst jetzt nach langem Schlafe nicht durchblicke ist folgendes:

Ich sende eine Variable per URL and die download.php

die sieht so aus:

download.php?file=Ppl/bahnengolf/Herzogenburg07_2006/IMG_0165.JPG

da hol ich mir dann in der Datei per basename() den Dateinamen raus und füge den in den Header-befehl ein:

$dlfl = basename($_GET[file]);

header("Content-Disposition: attachment; filename=$dlfl");


Logischerweise kennt sich das downloadscript jetzt absolut nicht mehr aus, weil es ja nicht weiss in welchem Verzeichniss die Datei "IMG_0165.JPG" liegt und wie mir ja schon mehrmals gesagt wurde, darf ich aber keinen Verzeichnisspfad in den Header schreiben! :(

Was die Verzeichniss- und Dateisicherheit angeht; So weit bin ich noch nichtmal gekommen! :dontknow:

Es ist schon schlimm dumm zu sein, aber wenigstens tut's nicht weh! *gg*

 
jahlives
22-09-2006, 18:33 
 
Dein Header Befehl würde aber einen Download verursachen und nicht die direkte Anzeige im Browser.
Und wieso kennst du den Pfad nicht ? Den haste ja immer noch in $_GET['file']. Aber wenn das Download Script direkt im Verzeichnis mit den Bildern liegt, dann brauchst du keinen kompletten Pfad sondern es reicht der Dateiname, weil PHP diesen Pfad dann als relativ betrachtet und das File im Verzeichnis sucht wo auch die PHP Datei liegt.

header("Content-type: image/jpg");
header("Content-disposition: inline; filename=$dlfl");

Müsste die Anzeige des Bildes erzwingen. Deine Version würde afaik erst einen Download erzwingen.

 
nichtsooft
22-09-2006, 18:39 
 
...würde einen Download erzwingen....
Darum heisst's ja auch "download.php" ;)
Und wenn man dann noch die vorangegangenen Posts gelesen hat weiss man auch, dass die download.php nicht im Verzeichniss mit den Bildern ist.
Genau das ist ja das Problem! :motz:

Edit: Wenn jmd nen Blick drauf werfen will: LINK zum Projekt (http://84.114.196.125/nsox/August/index.php?lang=de&section=5)

 
jahlives
22-09-2006, 18:46 
 
Und wenn man dann noch die vorangegangenen Posts gelesen hat weiss man auch, dass die download.php nicht im Verzeichniss mit den Bildern ist.

Sorry zu wenig genau gelesen. In diesem Falle brauchst du den Pfad um readfile() mitzuteilen welches Bild ausgelesen werden soll.
In den Header brauchst du aber den Pfad nicht, da geht's nur um den Namen mit dem das Bild beim Client gespeichert werden soll. Da kannst du schreiben was du willst...
Wenn ich auf deinen Link klicke und das Bild öffnen will, kann der Typ nicht bestimmt werden. Also fehlt dir ggf ein

header("Content-type: image/jpg");


Gruss

tobi

 
nichtsooft
22-09-2006, 18:52 
 
hmm...? Hab ich eigentlich eingebaut! :confused:

Aktuell:

<?php

// declare the basic directory for security reasons
// Please do NOT attach a "/"-suffix !
$dlfl = basename($_GET[file]);
$basedir = 'pics/galerie';
// $diradd = trim($path_parts['dirname'], $basedir);


////////// SECURITY
// compare the entered path with the basedir
// $path_parts = pathinfo($_REQUEST['file']);
// if ($diradd != 0) {
// ANTI-CRACK-ATTEMPT
// echo $_REQUEST['file'].'<br>';
// echo $path_parts['dirname'].'<br>';
// die ('coding good - h4x1ng bad!');}


// $datei = $_GET[file];
header("Expires: 0");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Content-Description: File Transfer");
header("Content-type: image/jpg");
header("Content-Disposition: attachment; filename=$dlfl");
header("Content-Transfer-Encoding: binary");
readfile($datei);
?>

 
kuddeldaddeldu
22-09-2006, 18:55 
 
Hi, gut geschlafen?

Jetzt verstehe ich, was Dein Problem ist:
Du verwechselst da etwas entscheidendes. Diese Header, die Du da
setzt, sind Response-Header. In einfachen Worten: Das sind Informationen,
die der Browser auswertet, um zu wissen, was er mit dem Content ,
der danach kommt, anstellen soll/kann. Diesen Content lieferst Du doch
schon mit Deinem readfile. Der Name, den Du da in dem Header einträgst,
ist nur ein Vorschlag für einen Namen. Stell Dir vor, Du klickst irgendwo
auf einen Download, ein Fenster geht auf, wo Du auswählen kannst,
wohin Du das speichern willst. Jetzt findest Du den vorgeschlagenen
Namen "steigerungsfähig" und änderst den. Meinst Du, der Download
funktioniert dann nicht? Du könntest das auch leer lassen, dann würde
da download.php oder download.html erscheinen.
Also, um es kurz zu machen:
In dem Header den Dateinamen setzen und dann
readfile(dateipfad).

So, und nun probier das einfach mal aus. Die Pfadüberprüfung sollte
sich dann nicht mehr so schwierig gestalten.

LG

 
nichtsooft
22-09-2006, 18:59 
 
*looool*

Soll's das wirklich gewesen sein!? *dasKeyboardMitVielSchwungAufMeineHohlbirneSchmetter*
Muss ich gleich mal versuchen! *kopfschüttel*

Naja: Wie gesagt: ...wenigstens tut's nicht weh!

 
kuddeldaddeldu
22-09-2006, 19:11 
 
Gerade gesehen:

In Deinem zuletzt geposteten Code machst Du ein readfile($datei),
obwohl Du die Variable nicht gesetzt bzw. auskommentiert hast.
*dasKeyboardMitVielSchwungAufMeineHohlbirneSchmetter*
...wenigstens tut's nicht weh!
Du bist schmerzfrei? :D

 
nichtsooft
22-09-2006, 19:18 
 
Anscheinend zu blöd um Schmerzen zu fühlen!

So weit klappt's mal, ABER:*gg*

Jeder kennt doch den FireFox Download-Dialog...

In diesem wird das Bild mit nem falschen Icon dargestellt! Nämlich: Anstelle des Icons für "JPG-Bilder" eines für "Unbekannte Datei". :(

Und jetzt muss ich zum Footballtraining... *stress*
Bin in 2h wieder da! Danke einstweilen allen die sich meiner so annehmen! :)

 
penizillin
22-09-2006, 19:20 
 
welchen Content-Type empfängt der browser?

 
nichtsooft
22-09-2006, 22:11 
 
Laut Header:

header("Content-type: image/jpg");

EDIT: Und hier liegt auch der Fehler! jpeg! Ergo:


header("Content-type: image/jpeg");


Und Problem behoben! :D

 
washu
23-09-2006, 01:15 
 
hallo ich weiss ja nicht was das gestreite soll aber ist dir jetzt geholfen oder nicht ?



ich würde es so machen kurz und knap!



header("Content-Type: application/octet-stream");
header("Content-Disposition: attachment; filename=\"".$_GET['Download']."\"");
readfile($_GET['Download']);

 
kuddeldaddeldu
23-09-2006, 01:25 
 
Hä?

 
washu
23-09-2006, 01:43 
 
wie hä er hatte doch ein problem mit sein Downloadscript oder nicht ?

 
subabrain
23-09-2006, 02:30 
 
oje ... was für ein Thread, hier hat man auch nicht an Postings gespart oder?

außerdem wurde solche Probleme doch schon sehr oft in diesem Forum besprochen - ich verstehs nicht :dontknow:

gruß
Robert

 
nichtsooft
23-09-2006, 09:38 
 
Hehe Leute!?

Es streitet doch niemand! Das problem ist fürs erste gelöst und an postings wurde eigentlich auch nicht gespart! Im gegenteil eigentlich. *gg*

Jetzt geht's irgendwie um die Sicherheit. Hat da jmd ne Anregung worauf ich achten soll/muss ("../" wird ja wohl nicht der einzige Faktor sein...)?

Lg. aus Wien.

 
3DMax
23-09-2006, 09:53 
 
Original geschrieben von nichtsooft
Jetzt geht's irgendwie um die Sicherheit. Hat da jmd ne Anregung worauf ich achten soll/muss ("../" wird ja wohl nicht der einzige Faktor sein...)?
wasserdicht wird es mit einem whitelistscheck, ala:

allowed=array('pic1'=>'blub/pi1.jpg', 'pic2'=>'pic2.jpg'); usw...

 
nichtsooft
23-09-2006, 12:45 
 
Hmm... gute Idee! Bloss...:

Kann ich diese Whitelist; öhm die ja ein Array ist auch irgendwie dynamisch erstellen?

So auf die Art:
$subz = array(Alle Subverzeichnisse von pics/galerie und deren Subverzeichnisse)
Und dann abchecken ob basename($file) Bestandteil von $subz ist!?

 
kuddeldaddeldu
23-09-2006, 13:15 
 
Hi,
Es streitet doch niemand!
Konnte ich auch nirgends entdecken...
Schau Dir die Dateisystem- und Verzeichnisfunktionen an. Du könntest
Dein Ausgangsverzeichnis rekursiv durchscannen und alles in das Array packen.
Eine Suche nach "Formulareingaben prüfen" o.ä. im Allgemeinen kann auch
nicht schaden. Da gibt es glaub ich schon Unzähliges.
LG

 
3DMax
23-09-2006, 20:39 
 
Original geschrieben von nichtsooft
[B]Kann ich diese Whitelist; öhm die ja ein Array ist auch irgendwie dynamisch erstellen?
als dynamische variante würde ich realpath() benutzen (hatte ich dir schon geschrieben) und dann zumindest noch die extension (jpg) prüfen.


Alle Zeitangaben in WEZ +2. Es ist jetzt 20:49 Uhr.