PHP direkten download über url verhindern

koffi

Lt. Junior Grade
Registriert
Jan. 2007
Beiträge
490
hallo zusammen!

ich habe eine internetseite auf der dateien sind. ich möchte jedoch nicht, dass diese dateien einfach heruntergeladen werden können indem man die url in die browserzeile eingibt, also zb meineseite.de/files/einedatei.doc

grund ist, dass ich nur registrierten benutzern download gewähren will und jeden download in einer datenbank protokolliere.

ich habe das über php gelöst, wie folgt:

Code:
if ($user->id != ''){

       //datenbank eintrag, protokolliere download
       $eintrag = mysql_query("INSERT INTO downloads (fb_id, fb_name, file_id, file_name) VALUES ('".$user->id."', '".$user->name."', '".$download_id."', '".$row1['name']."')   ");   

      
       //automatischer download   
          $Datei = substr($row1['link'],21);   //also in diesem fall files/einedatei.doc
          $Dateiname = basename($Datei);
          $Groesse = filesize($Datei);
          header("Content-Type: application/force-download");
          header("Content-Disposition: attachment; filename=".$Dateiname);
          header("Content-Length: $Groesse");
          readfile($Datei);
      } else {echo 'you dont have permission do download files.';};

funktioniert soweit super.
nur, wie kann ich nun verhindern dass leute dateien wie oben beschrieben runterladen, also über eintippen des links in die browserzeile..?
 
warum einfach wenn es auch kompliziert geht? ^^

einfach passwortschutz auf den ordner mit den dateien - fertig.
 
impressive schrieb:
warum einfach wenn es auch kompliziert geht? ^^

einfach passwortschutz auf den ordner mit den dateien - fertig.
Dann müssen aber alle entweder alle User für den PW-Schutz eingetragen werden (hoher Aufwand) oder alle das gleiche PW, dann könnte aber jeder der das PW kennt auch ohne registriert zu sein downloaden. Ausserdem wird dann nicht mehr protokolliert wer was runtergeladen hat.

BTT: Verzeichnis mit .htaccess schützen.
 
Warum so kompliziert?

Nur registrierten usern? Super! Beim einloggen Benutzer_ID in der Session speichern und die Abfragen. Sowas wie

PHP:
if($_SESSION["user_id"]>0) {
   ....//download skritp
}
else
{
header(Location: .....) //Login-Seite
}
 
Ja so geht es über die Seite, aber wenn du die URL der Datei kennst, kannst du sie trotzdem ohne gültigen Login herunterladen.
 
Nein eben nicht, weil wenn du nicht eingeloggt bist das Download-Skript im If-Block nicht aufgerufen wird sondern weil du zur Login-Seite weitergeleitest wirst.

Seh gerade du fragst schon die Session ab. Dann packs in nem Unterordner wo es nich klar rausgeht oder so und ruf das ganze nur über nen Get-Parameter auf. Sowas wie download.php?file=einedatei.doc und das ganze ist dann in /var/www/files/downloads/bla/einedatei.doc
 
@chriz0101: Und es geht eben doch, wie Yuuri meint. Wer die URL zur Datei hat, darum gehts.

Wenn du möchtest, dass es nicht geht, musst du den effektiven Pfad zur Datei andauernd ändern. Zb. indem du symlinks auf die eigentliche Datei machst, welche du ab und zu änderst oder so.

Edit: Nicht, dass das effektiv verhindern würde, dass andere es so downloaden könnten. Aber es beschränkt es zumindest zeitlich.

Computerbase Downloads funktionieren übrigens auch so ähnlich, soweit ich sehe.

Achja, und so wie im ersten Post per readfile()... Das halte ich für gar keine gute Idee. Kommt zwar draufan wie gross die Dateien sind, aber... Für die gesamte Downloaddauer muss das php Script laufen. Vergiss nicht die Max Execution Time. Und Resourcen werden auch ein paar zuviel verschwendet.
 
Zuletzt bearbeitet:
chriz0101 schrieb:
Nein eben nicht, weil wenn du nicht eingeloggt bist das Download-Skript im If-Block nicht aufgerufen wird sondern weil du zur Login-Seite weitergeleitest wirst.
Doch, eben doch.

Sagen wir der Webspace liegt in /www/htdocs/user123/meine-domain-123/files/irgdend/ein/weiterer/pfad/datei.doc, so kann ein unbedarfter User, der die URL nicht kennt, die Datei nur über das Frontend herunterladen. Ein klein wenig bedarfter User, kann sich beim Download (nach einer Umleitung auf diese Datei) eben den Downloadlink kopieren und dann mittels http://meine-domain-123.de/files/irgdend/ein/weiterer/pfad/datei.doc ohne validen Login herunterladen. Das kannst du nur mittels htaccess umgehen, da somit nur der PHP User Zugriff auf diese Datei hat (da über den Pfad und nicht die URL angesprochen), nicht aber ein "Internet User", der direkt auf die Datei zugreifen will.
 
Hallo @ all

habe zwar gerade keinen Code zur Hand, aber wie wäre es mit einem zeitlich begrenzten Download? Man könnte, nachdem ein authorisierter Benutzer den Download gestartet hat, die Datei in einen tempordner verschieben und dort nach z.b. 1 Std wieder löschen. Der ursprüngliche Pfad der datei bleibt .htaccess geschützt. Für die zeitliche Steuerung eine Tabelle in die DB, hier wird gespeichert, welche Datei wann geladen wurde und wann die Deadline vorbei ist. Bei jedem Aufruf der Seite oder per cronjob wird gecheckt was gelöscht werden kann.
Is abe nur für relativ kleine Dateien ok, da bei 10 GB per Modem sicherlich das Zeitlimit überschritten wird.

edit: Stichwort copy();
 
Zuletzt bearbeitet:
Leg die Dateien in einem Verzeichnis ab, das außerhalb des Document Root liegt (also nicht unterhalb von htdocs). Dann gibt es keinen URL, über den man direkt an die Datei herankäme.
 
htacces war schon der richtige Ansatz; leg die Datei in einen geschützten Ordner, dann kann niemand die datei manuell aufrufen, dein PHP kann aber wie gewohnt die Daten ausliefern. Die meisten Webspacepakete erlauben zudem Dateien in Ordnern zu speichern, die nicht per Browser abrufbar sind.
 
Also ich würde die Dateien nicht direkt im FileSystem speichern. Falls du eine DB zur Verfügung hast speicher sie dort drin. Habe das vor kurzem in einem Projekt gemacht, das war zwar .NET und MS SQL Server aber das geht bestimmt auch mit PHP und XY DB Server:

Der Download der Dateien geht nur über ein Download script. Diesem Script wird als Parameter ein Dateiname/Pfad übergeben. Das Script überprüft die Permissions und lädt dann den FileStream aus der DB und gibt diesen für den Download dem Clienten. Der Dateiname/Pfad ist dabei ein Feld in der DB und die User liegen wahrscheinlich ja auch schon in der DB, wodurch du die "Files" Tabelle nur durch eine "Permissionstabelle" mit der User Tabelle verknüpfen brauchst.
Der Vorteil wäre du kannst in der DB gleich mitloggen wer was geladen hat und wann. Im SQL Server kann man den FileStream sogar aus der DB wieder auf eine HDD auslagern, so das deine DB Datei nicht zu groß wird. Geht vllt auch in MySQL / Postgre.

Der Vorteil dieser Lösung ist, dass der Download nicht mehr am "Anwendungskontext" vorbei geht, sondern selber durch deine Anwendung gemacht wird.
 
Zuletzt bearbeitet:
kelox schrieb:
Also ich würde die Dateien nicht direkt im FileSystem speichern. Falls du eine DB zur Verfügung hast speicher sie dort drin.
Ein Dateisystem wurde für Dateien erschaffen, eine Datenbank für alle möglichen Daten. Natürlich sind in DBs auch BLOBs möglich, aber es heißt eben Datenbank und nicht Dateisystem.

Gibt genügend Einträge in Google darüber mit der Konsequenz: Blödsinn.
 
Yuuri schrieb:
Ein Dateisystem wurde für Dateien erschaffen, eine Datenbank für alle möglichen Daten. Natürlich sind in DBs auch BLOBs möglich, aber es heißt eben Datenbank und nicht Dateisystem.

Gibt genügend Einträge in Google darüber mit der Konsequenz: Blödsinn.

Naja, es war auch nur unter dem Punkt gesehen, dass er eben diese Blobs von seiner DB wieder aufs FS Schreiben lassen kann. Beim MS SQL Server heißt das Remote Blob Storage http://msdn.microsoft.com/en-us/library/gg316768.aspx bzw FILESTREAM Datentyp. Sowas gibs bestimmt auch bei MySQL und Co. Falls es das natürlich nicht gibt, ist es halt mit gewissen Limitierungen versehen.
 
Zuletzt bearbeitet:
Wieso mit htacess? Wie wärs schlicht und ergreifend damit die Dateiberechtigung auf 700 zu stellen, dann darf nur noch der Server/ das Skript drauf zugreifen....
So oder so würde ich dir empfehlen Die Dateien ohne Dateiendung und nur mit einem einzigartigem md5 hash als Namen abzuspeichern. Selbst wenn man die Datei dann noch aufrufen könnte, hat sie a keine Dateiendung und b weiß keiner wie die Datei heißen soll. Da du das ganze ja sowieso in der DB abspeicherst kannst du auch dort den richtigen Namen der Datei und am besten noch einen vom Benutzer gewählten Namen abspeichern.

Und von einer Speicherung in der Datenbank kann ich nur abraten und sie ist auch in diesem Fall überhaupt nicht nötig, im Zweifelsfall überforderst du damit eher deinen Datenbankserver.
 
GreenGene schrieb:
Wieso mit htacess? Wie wärs schlicht und ergreifend damit die Dateiberechtigung auf 700 zu stellen, dann darf nur noch der Server/ das Skript drauf zugreifen....

ja, und genau das reicht doch aus, um die Daten übers Internet zu senden: Der Webserver darf es lesen, er darf es an jeden schicken.
 
Ich denke auch zeitliche begrenzte Downloads sollten das möglich machen.
Aber nicht über copy(), das würde viele Ressourcen schlucken.

Ich meine mit mod_rewrite und evtl. einer dynamischen .htaccess sollte das hinkriegen.
 
Dateien in der Datenbank speichern ist ja wohl kompletter Blödsinn, ob mit MySQL oder MS SQL. Das macht niemals wirklich sinn.

@GreenGene: Wie ice-breaker schon sagt. Mode 700 bringt gar nix, .htaccess oder in einem Verzeichnis welches nicht im Webroot ist. Und den Typ einer Datei findet man übrigens nicht nur über deren Endung heraus.
 
@icebreaker Der Webserver soll doch auch drauf zugreifen können, der Benutzer aber nicht direkt über die URL wo ist das Problem? Falls du damit aber meintest, dass auch Benutzer einfach über Adresseingabe auf die Datei zugreifen können, dann würde ich gerne mal wissen wieso das bei mir nicht funktioniert.

@bu1137 Man kann das auch anders raus finden ja, aber es ist nochmal etwas schwieriger...

403: Forbidden, Verboten, Unzulässig; Zugriff für den Rechner des User gesperrt <-- Wikipedia
 
Zuletzt bearbeitet:

Ähnliche Themen

Zurück
Oben