1. Liebe Forumsgemeinde,

    aufgrund der Bestimmungen, die sich aus der DSGVO ergeben, müssten umfangreiche Anpassungen am Forum vorgenommen werden, die sich für uns nicht wirtschaftlich abbilden lassen. Daher haben wir uns entschlossen, das Forum in seiner aktuellen Form zu archivieren und online bereit zu stellen, jedoch keine Neuanmeldungen oder neuen Kommentare mehr zuzulassen. So ist sichergestellt, dass das gesammelte Wissen nicht verloren geht, und wir die Seite dennoch DSGVO-konform zur Verfügung stellen können.
    Dies wird in den nächsten Tagen umgesetzt.

    Ich danke allen, die sich in den letzten Jahren für Hilfesuchende und auch für das Forum selbst engagiert haben. Ich bin weiterhin für euch erreichbar unter tti(bei)pcwelt.de.
    Dismiss Notice

direkten downloadlink verhindern

Discussion in 'Web-Know-how für die Homepage' started by binauchhier, Sep 25, 2006.

Thread Status:
Not open for further replies.
  1. binauchhier

    binauchhier Kbyte

    Ich hätte da eine Frage an die Erfahrenen hier im Forum:
    Ist es sinvoll, Downloads in der Form vor direktem Verlinken zu schützen, dass mit einem php-Script eine Variable (Zahl) übergeben wird, die aus dem Aktuellen Datum erzeugt wird, also in der Art:
    PHP:
    ?id=mktime(000date("m")  , date("d"), date("Y"))/8-67*9
    und das Script, was den Download ausliefern soll überprüft dann, ob die Zahl richtig ist?

    Danke
    binauchhier
     
  2. kalweit

    kalweit Hüter der Glaskugel

    Nö. Zum einen ist das Verfahren für den User sichtbar und zum anderen blockierst du sämtliche Cachemöglichkeiten -> am Ende kommt u.U. mehr Traffic auf die Leitung, als ohne "Sicherung". Es stellt sich immer die Frage, welches Ziel mit so einer Aktion verfolgt werden soll? In der Regel sind Sessions das Mittel der Wahl.
     
  3. binauchhier

    binauchhier Kbyte

    Sessions kann ich nicht - leider. Dachte, dass es sichtbar ist, macht nichts, da man ja erstmal die Rechenoperationen rauskriegen muss...
    An dem zusätzlichen Traffic ist aber was dran, wobeis mir darum gar nicht so stark geht, sondern mehr darum, dass jeder die Seite besuchen muss.
     
  4. Michi0815

    Michi0815 Guest

    Ich würde es über den referrer machen...
     
  5. kalweit

    kalweit Hüter der Glaskugel

    Das bringt nichts - der Referer ist Teil des HTTP-Headers und kann vom Client [1] beliebig geändert werden.

    [1] Ein Client kann z.B. auch ein Serverscript sein.
     
  6. kalweit

    kalweit Hüter der Glaskugel

    Nö. Dein Hashwert ist doch 24 Stunden gültig. Für den "Einbruch" brauche ich deine Rechnung nicht wissen:

    1) ich setze auf meiner Seite einen Downloadlink
    2) dieser führt nicht direkt auf dein Downloadscript, sondern auf ein Script von mir
    3) dieses "checkt" um 0 Uhr deine Downloadseite und merkt sich den Hash
    4) mein Downloadscript erstellt darauf hin einen Header/Seite (je nach Wunsch) mit deinem gültigen Download und leitet den User entsprechend weiter
     
  7. binauchhier

    binauchhier Kbyte

    Ich merke schon, ich denke nicht kriminell genug :D Da ist es warscheinlich auch nicht sicherer, wenn ich den Hash als Scheinverzeichnis nutze, in dem die Datei liegen soll...
    Jedenfalls Danke für die Hilfe!
     
  8. kalweit

    kalweit Hüter der Glaskugel

    In der "Ebene" sind wir noch lange nicht... ;)
     
  9. Michi0815

    Michi0815 Guest

    lass doch die kirche im dorf, es soll - zumindest lese ich das so - einfach nur verhindert werden, dass der download durch einen link in einem forum/blog/etc angestoßen werden kann.

    dass sich mit genug motivation so ziemlich jede sperre umgehen lässt ist mir schon klar ;)
     
  10. kalweit

    kalweit Hüter der Glaskugel

    Ähm - es verlinkt doch nur jemand "direkt", wenn das Ziel interessant genug dafür ist. Ist es das nicht, wird keiner darauf verlinken. Demnach: wenn man Überlegungen zum Downloadschutz anstellt, geht man vom ersten Fall aus (= Motivation für den Verlinkenden hinreichend vorhanden) - ansonsten ist das Ansinnen aus sich heraus sinnfrei. Halbgare "Sicherheitskonzepte" halte ich für gefährlich.
     
  11. binauchhier

    binauchhier Kbyte

    Jetzt habe ich mir doch mal die Sessions angeschaut.
    Falls mir da nochmal jemand auf die Sprünge helfen könnte wäre super!

    Was ich nicht verstehe:
    Warum kann niemand die Datei direkt downloaden, wenn ich Sessions verwende?
    Und warum geht es, wenn ich die im ersten Post von mir vorgeschlagenen Variante mit einem Zeitstempel verwende? Die SID ist ja per default auch 1 Tag gültig und kann von jedermann verwendet werden?

    Also, so habe ich es jetztmal gelöst:
    Der Download wird so gestartet:
    PHP:
    $_SESSION['dlok'] = "gehtklar";
    <
    a href="./?datei='.$number.'&amp;SID='.session_id().'"
    ...
    Die SID wird als String übergeben, da mir die Prüfung, ob Cookies angenommen werden, zu umständlich ist.

    Wenn ich dem Link folge wird die Datei mit folgendem Code ausgeliefert:
    (Ab hier ungekürzt, wenns zuviel ist reduzier ich den Code auch gerne nochmal aufs nötigste)
    PHP:
    $ddir ="dateien/"// Verzeichnis mit den Downloads
    $file $_GET['datei'];

    if ( 
    $_GET['datei'] && ($_SESSION['dlok'] == "gehtklar")) {
        
    $fileTyp = array("jpg","gif");
        
    $pictures = array();
        
    $Bildergalerie scan_dir($ddir,$fileTyp,FALSE,TRUE,TRUE,$onlyDir$pictures,0);
        if ((
    $Bildergalerie != false)) 
            
    call_user_funcdlFile,$Bildergalerie);
        
    header("HTTP/1.0 404 Not Found"); 
        echo 
    "Fehler 404: Datei nicht gefunden";
        exit();
    }
    if(( 
    $_GET['datei'])&& ($_SESSION['dlok'] != "gehtklar") ) {
    echo <<<END
        <html><head></head><body>
        Du warst zu lange nicht auf dieser Seite. Bitte gehe zur <a href="./">Downloadseite</a> und
        lade
        diese nochmals neu.
        </body></html>
        
    END; 
        exit();
    }
    Mit der Funktion dlFile:
    PHP:
    function dlFile($pictures)
    {
        
    reset ($pictures);
        foreach(
    $pictures as $key => $array
        {
            foreach (
    $array as $key2 => $array1
            {
                if ((
    $number == $_GET['datei']) && !empty($pictures[$key][$key2]['file'])) {
                
                    
    $path            $pictures[$key]['name']['path'].$pictures[$key][$key2]['file'];
                    
    header("Content-type: application/octet-stream");
                    
    header("Content-Disposition: attachment; filename=".urlencode($pictures[$key][$key2]['file']));
                    
    header("Content-Length: ".filesize($path));
                    
    header("Cache-Control: no-cache, must-revalidate"); // HTTP/1.1
                    
    header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); // Datum in der Vergangenheit
                    // Datei ausgeben:
                    
    readfile($path);
                    exit();
                }
            }
        }
    }

    ?>
    Ich gehe jetzt mal davon aus das ich keine Sicherheitslücken im übrigen Code fabriziert habe.


    Danke schonmal für eine Antwort!
     
  12. kalweit

    kalweit Hüter der Glaskugel

    Ein paar Dinge vorweg:

    - deine Session ist nicht initialisiert (zumindest laut deinem Code)
    - file_exists() existiert und kann unabhängig vom Webspace agieren, so dass du dir das Schleifengedöhns komplett sparen kannst

    Du hast das Wesen einer Session nicht erfasst, sonst würde dir nämlich aufgehen, dass für jeden User/Request eine eigene Session mit eigener Session-ID erstellt wird - d.h. session_id() liefert für jede Anfrage einen anderen Wert (es sei denn, die Session ist seitens des Users bereits vorhanden).

    Quatsch! PHP kann dies seit der Version 3.irgendwas komplett automatisch - d.h. im konkreten Fall, muss die Session-ID überhaupt nicht am Link erscheinen (vermutlich rührt daher das Verständnisproblem).

    Naja, $_GET['datei'] sollte man mal nach möglichen Schwachstellen abklopfen, da du selbiges ohne Prüfung direkt in deinem(? - macht mir eher einen zusammenkopierten Eindruck) Script verwendest. Ansonsten (mal schnell zusammengestümpert):

    PHP:
    $dir="irgendwas/";

    // fängt die gröbsten Einbruchstellen ab
    $file=strip_tags(addslashes($_GET["datei"]));

    session_start();
    if (
    $_SESSION['dlok'] = "gehtklar") {
    if (
    file_exists($dir.$file) {
    // hier kommen die header und fertig
    } else echo "gibt's nicht";
    } else echo 
    "du darfst nicht";
    ...natürlich setzt das vorraus, dass sich die Dateien außerhalb des Webspace befinden oder zusätzlich per .htaccess vor direktem Zugriff abgehängt sind.
     
  13. binauchhier

    binauchhier Kbyte

    Vielen Dank für die ausführliche Antwort! Darf ich gleich noch eine genauso ausführliche Frage anhängen? Falls du dafür noch zeit hättest wär echt super!
    Ich bin noch dabei, php zu lernen und deswegen ist mir -leider- nicht immer alles gleich klar.
    session_start(); stand ganz am anfang der Seite, war nur sehr viel Code dazwischen... sorry

    Ich dachte, eine Session ist so konzipiert, dass sie erlischt, wenn ich den Browser schließe und auch ungültig wird, wenn ich sie mit einem anderen Browser von einer anderen IP aus aufrufe. Allerdings ist die an die URL angehängte SID auch über diese Grenzen hinweg gültig. Das verstehe ich nicht?(Und wenn ich sie nicht als Paramater übergebe, macht das PHP ganz automatisch :( )

    Da hat du recht, der Code ist zusammenkopiert und auf meine Bedürfnisse angepasst. Ich dachte, wenn sich jemand anderes diese Arbeit schon gemacht hat, brauche ich das nicht nocheinmal tun :)
    zu $_GET['datei']: Das ist, wenn korrekt übergeben, eine Zahl, die nicht verarbeitet wird, sondern nur zum Vergleichen in der Funktion dlFile dient (Die Dateien werden aus dem Downloadverzeichnis erst ausgelesen und nummeriert in ein Array geschrieben, dann sucht die Funktion dlFile sich die Datei mit der richtigen Nummer raus[ok, das könnte man auch noch optimieren])
    Muss ich in diesem Fall $_GET['datei'] daraufhin überprüfen, ob es eine Zahl ist? Sie wird ja nicht weiterverarbeitet sondern dient nur zum Vergleichen?

    Dein Tipp zur Vereinfchung der Schleifen war hilfreich, danke! Leider kann ich aber nicht alle löschen, da weiter unten in der Datei die Übersicht über alle Downloads erzeugt und ausgegeben wird. Das elsif unten muss deswegen so oder ähnlich bleiben. Und ok, die Funktion dlFile ist eigentlich überflüssig, macht aber den Code (find ich) etwas übersichtlicher.
    Verzeichnisschutz ist mit .htaccess gemacht
    Code:
    <Limit GET POST PUT>
    Order Allow,Deny
    Deny from All
    </Limit>
    ICh poste grad nochmal meinen Code hierhin:
    PHP:
    // Holt sich den passenden Download aus dem Array
    function dlFile($pictures)
    {
        
    reset ($pictures);
        foreach(
    $pictures as $key => $array
        {
            foreach (
    $array as $key2 => $array1
            {
                
    $path $pictures[$key]['name']['path'].$pictures[$key][$key2]['file'];
                if ((
    $pictures[$key][$key2]['number'] == $_GET['datei']) && file_exists($path)) {
                    global 
    $dateiname;
                    global 
    $dateiort;
                    
    $dateiort $path;
                    
    $dateiname urlencode($pictures[$key][$key2]['file']);
                }
            }
        }
    }
    //
    //
    //
    $ddir ="dateien/"// Verzeichnis mit den Downloads
    $file $_GET['datei'];

    // Wenn eine Datei angefordert wird
    if ( $_GET['datei'] && ($_SESSION['dlok'] == "gehtklar")) {
        
    // Parameter für den Aufruf von $Bilderglerie
        
    $fileTyp = array("pdf","jpg","gif");
        
    $pictures = array();
        
    $Bildergalerie scan_dir($ddir,$fileTyp,FALSE,TRUE,TRUE,$onlyDir$pictures,0);
        if ((
    $Bildergalerie != false)) // Falls keine Dateien existieren -> vermeidet eine Fehlermeldung
            
    call_user_funcdlFile,$Bildergalerie);
        if (
    file_exists($dateiort)) {
            
    header("Content-type: application/octet-stream");
            
    header("Content-Disposition: attachment; filename=".$dateiname);
            
    header("Content-Length: ".filesize($dateiort));
            
    header("Cache-Control: no-cache, must-revalidate"); // HTTP/1.1
            
    header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); // Datum in der Vergangenheit
            // Datei ausgeben:
            
    readfile($dateiort);
            exit();
        }
        else {
            
    header("HTTP/1.0 404 Not Found"); 
            echo 
    "Fehler 404: Datei nicht gefunden";
            exit();
        }
    }
    elseif(( 
    $_GET['datei'])&& ($_SESSION['dlok'] != "gehtklar") ) {
        echo 
    "Seite mit: du darfst nicht";
        exit();
    }
     
Thread Status:
Not open for further replies.

Share This Page