phpbar.de logo

Mailinglisten-Archive

RE: [php] Sicherheitsfrage: Files mit PHP vor download schützen

RE: [php] Sicherheitsfrage: Files mit PHP vor download schützen

Andreas Demmer php at andreas-demmer.de
Mit Sep 22 09:51:56 CEST 2004


Tobias wrote:

>> Was, wenn jemand die Position des Files genau kennt und diese in die
>> Adressleiste des Browsers eingibt. Dann bringen mir die bisherigen
>> Lösungen ja nichts, oder täusche ich mich.

Anbei meine Lösung. Die Dateien liegen nicht im verlinkten Verzeichnis media
(/media/1a2b3c4d5e.jpg) sondern in einem Verzeichnis ausserhalb des
Webroots.
Im Rootverzeichnis liegt eine .htaccess, die alle Zugriffe auf das virtuelle
Verzeichnis /media/, welches nicht existiert, auf eine Datei "media"
umleitet
und die mit PHP parst:

<Files media>
  ForceType application/x-httpd-php
</Files>

In der media prüfe ich nun, ob der Benutzer wirklich von meiner Seite kommt
(in Deinem Falle ob er eingeloggt ist) und liefere die Datei aus. Zusätzlich
hole ich noch einige Infos (echten Dateinamen etc.) aus der Datenbank, aber
auch das könnte man kürzen. Falls der Benutzer nicht eingloggt ist wird ein
deny.png ausgeliefert. In diesem kann man dem Leecher freundlich darauf hin-
weisen, dass er einloggt sein muss (in meinem Fall dass er nicht von meiner
Domain kam).

<?php
/**
* midgetCMS Medien-Feeder 1.2.0
*
* liefert die von der URL angeforderten Medien aus,
* sofern die Anforderung von der eigenen Domain kam
*
* @author Andreas Demmer <mail at andreas-demmer.de>
*/
include_once($_SERVER['DOCUMENT_ROOT'].'/includes/config.inc.php');
include_once(PATH_INCLUDES.'functions.inc.php');
require_once(PATH_INCLUDES.'class_visitor.inc.php');
require_once(PATH_INCLUDES.'class_database.inc.php');
require_once(PATH_INCLUDES.'class_debugconsole.inc.php');

$__debugConsole_enable = FALSE;
@session_start();

// Besucherzugriff protokolliert? Wenn ja: Medien freischalten
$visitor = new visitor($_SERVER['REMOTE_ADDR']);

if($visitor->isRegistered()) {
    $params = explode('/', $_SERVER['REQUEST_URI']);
    $filename = array_pop($params);

    if(strpos($filename, '?')) {
        $filename = substr($filename, 0, strpos($filename, '?'));
    }
} else {
    $filename = 'deny.png';
}

$suffix = substr($filename, strrpos($filename, '.') + 1);
$filepath = PATH_UPLOADS.$filename;

if(!file_exists($filepath)) {
    die('ERROR 404: file "'.$filename.'" not found!');
}

// vorgegebenen Dateinamen ermitteln
$db = new Database();

$sql = 'SELECT title
          FROM '.DB_TABLE_MEDIA.'
         WHERE filename = \''.$filename.'\'';

$result = $db->query($sql);
$result = $db->fetchAssoc($result);
$title = urlencode($result['title']);

$virtualFilename = $title.'.'.$suffix;
header('Content-Disposition: filename='.$virtualFilename);

// Ausgabe der Medien-Datei mit korrektem Header
if(preg_match('|^jpe*g$|i', $suffix)) {
    // JPG Bild
    header('Content-type: image/jpeg');
} elseif(preg_match('|^gif$|i', $suffix)) {
    // GIF Bild
    header('Content-type: image/gif');
} elseif(preg_match('|^png$|i', $suffix)) {
    // PNG Bild
    header('Content-type: image/png');
} elseif(preg_match('|^pdf$|i', $suffix)) {
    // PDF Dokument
    header('Content-Type: application/pdf');
} else {
    // unbekannter Medientyp
    header('Content-Type: application/octlet-stream');
}

readfile($filepath);
exit;
?>

So könnt Ihr es ausprobieren: Ruft folgende URL auf:
http://www.andreas-demmer.de/media/a9583cc6d1.png

Eine Zugriffsverletzung sollte erscheinen. Besucht
http://www.andreas-demmer.de und ruft den Pfad
http://www.andreas-demmer.de/media/a9583cc6d1.png
erneut auf, diesmal sollte es gehen.

Gruss,
Andreas

--
http://www.andreas-demmer.de



php::bar PHP Wiki   -   Listenarchive