Marina G.: Sicherer Download

Hallo nettes Forum,

ich möchte einen sicheren Download porgrammieren,
wie geht den das???

Ich habe einen Bereich auf meiner Homepage, der durch
Kennwort & Passwort geschütz ist. Der Besucher gibt
auf einem HTMLFormular K&PW ein. PHP überprüft die
richtigkeit der Daten. Danach kommt man auf eine
Seite, auf der sich der Link zu einem Download befindet.
Jetzt komme ich zu meiner eigentlichen Frage:
Nur wenn jemand diesen Link anklickt, bekommt den
Download angeboten. Wir kann ich dies realisieren?
Ich habe Null Ahnung ;-( wie ich den Download schützen kann.

Bin für jeden Tip dankbar.

cu all

  1. Hi!

    Ich habe einen Bereich auf meiner Homepage, der durch
    Kennwort & Passwort geschütz ist. Der Besucher gibt
    auf einem HTMLFormular K&PW ein. PHP überprüft die
    richtigkeit der Daten. Danach kommt man auf eine
    Seite, auf der sich der Link zu einem Download befindet.
    Jetzt komme ich zu meiner eigentlichen Frage:
    Nur wenn jemand diesen Link anklickt, bekommt den
    Download angeboten. Wir kann ich dies realisieren?
    Ich habe Null Ahnung ;-( wie ich den Download schützen kann.

    Lege die Dateien, die du zum Herunterladen freigeben möchtest in ein Verzeichnis, in dem sich außerdem folgende .htaccess Datei befindet:

    Order allow,deny
    Deny from All

    Damit wird jeder Zugriff auf HTTP-Ebene verhindert, PHP kann jedoch weiterhin auf jene Dateien zugreifen, da dies auf der Ebene des Dateisystems stattfindet. Erstelle aus diesem Grund ein PHP-Skript, das als GET-Parameter einen Dateinamen erwartet, überprüft, ob diese Datei existiert und zudem noch schaut ob der User berechtigt ist, jene Datei herunterzuladen (z.B. mit der Verwendung von Sessions). Treffen alle diese Bedingungen zu, so wird der richtige Content-Type-Header an den Client geschickt und die Datei z.B. mittels readfile() ausgegeben.

    Grüße,
    Fabian St.

    1. Hi,

      DANKe für die Antwort.

      Bis hierher habe es verstanden, kannst Du mir bitte diesen Teil noch etwas näher erklären:

      Treffen alle diese Bedingungen zu, so wird der richtige Content-Type-Header an den Client geschickt und die Datei z.B. mittels readfile() ausgegeben.

      Gruß
      Marina

      1. hi!

        Ich bin zwar nicht Marina, mich interessiert es aber auch

        wenn ich die .htaccess-Datei in den Ordner einfüge, auf welche chmod stell ich diesen Ordner dann?

        ich glaube dieser Code müsste den Zweck erfüllen (ich hoffe ich hab keine fehler reingeschrieben, aber bei allg. lesezugriff => 777 und keine htaccess-Datei funktionierts

        <?PHP  
           $application = $_GET['application'];  
           $dateiname = $_GET['dateiname'];  
           header("Content-type: application/$application");  
           header("Content-Disposition: attachment; filename=".$dateiname.".".$application."");  
           readfile("../files/$dateiname.$application");  
        ?> 
        

        Danke
        Roland

        1. Hallo Roland,

          <?PHP

          $application = $_GET['application'];
             $dateiname = $_GET['dateiname'];
             header("Content-type: application/$application");
             header("Content-Disposition: attachment; filename=".$dateiname.".".$application."");
             readfile("../files/$dateiname.$application");
          ?>

            
          Auch, wenn dein Code funktioniert, so steckt er doch voller Sicherheitslücken.  
          Ich könnte damit auf Anhieb alle Dateien auslesen, auf die der Server zugreifen kann.  
          Der Fehler: Du prüfst die Inhalte der Variablen nicht.  
            
            
          Grüße  
            
          Marc Reichelt || <http://www.marcreichelt.de/>  
          
          -- 
          Linux is like a wigwam - no windows, no gates and an Apache inside!  
            
          Selfcode: ie:{ fl:| br:> va:} ls:< fo:} rl:( n4:( ss:) de:> js:| ch:? sh:| mo:) zu:)  
          <http://emmanuel.dammerer.at/selfcode.html>
          
          1. Hallo Marc,

            Auch, wenn dein Code funktioniert, so steckt er doch voller Sicherheitslücken.
            Ich könnte damit auf Anhieb alle Dateien auslesen, auf die der Server zugreifen kann.

            Tatsächlich? Aber nur, wenn du sie namentlich kennst.
            Oder kann readfile() auch Verzeichnisinhalte lesen?

            Der Fehler: Du prüfst die Inhalte der Variablen nicht.

            Das ist auf jeden Fall eine gefährliche Nachlässigkeit.
            So long,

            Martin

            1. hi!

              ich verwendes ja auch noch nicht, sondern habs nur mal im Forum gepostet!

              Was muss ich bei chmod angeben, damit php daten reinschrieben und lesen kann?

              Kann mir vielleicht jemand einen sicheren code geben? (Und selbst wenn dieser obige Text sicherheitslücken hat ist es doch relativ unwahrscheinlich, dass jemand ohne eine kenntniss über den Code und ohne Ahnung, in welchem Ordner er sich gerade befindet es schafft diese funktion ausznützen ...

              thx
              Roland

              1. Moin!

                ich verwendes ja auch noch nicht, sondern habs nur mal im Forum gepostet!

                Trotzdem, es gibt hier einige wie mich, für die Sicherheit ein Paradigma ist.

                Was muss ich bei chmod angeben, damit php daten reinschrieben und lesen kann?

                Tja, dann wirst du wohl nicht um 777 herumkommen, weil der Webserver normalerweise mit Benutzer- und Gruppen-Rechten läuft, die du nicht hast. Aber informier doch vorher bei deinem Webhoster.

                Kann mir vielleicht jemand einen sicheren code geben?

                  
                <?php  
                $ordner = '/pfad/zu/meinen/Downloads/';  
                $datei  = basename($_GET['dateiname']);  
                  
                header('Content-Type: application/octet-stream');  
                header('Content-Disposition: attachment; filename=' . $datei);  
                  
                readfile($ordner . $datei);  
                ?>  
                
                

                (Und selbst wenn dieser obige Text sicherheitslücken hat ist es doch relativ unwahrscheinlich, dass jemand ohne eine kenntniss über den Code und ohne Ahnung, in welchem Ordner er sich gerade befindet es schafft diese funktion ausznützen ...

                Das glaubst du >:->

                Viele Grüße,
                Robert

            2. Hallo Martin,

              Ich könnte damit auf Anhieb alle Dateien auslesen, auf die der Server zugreifen kann.

              Tatsächlich? Aber nur, wenn du sie namentlich kennst.
              Oder kann readfile() auch Verzeichnisinhalte lesen?

              Naja, es reicht aber doch, wenn mir readfile zum Beispiel die index.php des Hauptverzeichnisses liefert? Die wurde dann doch - wenn ich es richtig verstehe - noch nicht geparst. Und da suche ich mir dann halt alle Dateinamen zusammen...

              liebe Grüße mbr

              1. Hi,

                Naja, es reicht aber doch, wenn mir readfile zum Beispiel die index.php des Hauptverzeichnisses liefert? Die wurde dann doch - wenn ich es richtig verstehe - noch nicht geparst.

                das ist soweit richtig. Aber damit kannst du noch lange nicht "alle Dateien auslesen, auf die der Server zugreifen kann" (Marc Reichelt), sondern nur die, die in diesem PHP-Script bzw. der index.html referenziert werden. Alle anderen Dateinamen müsste ich immer noch erraten, denn aus den HTML- oder PHP-Quelltexten geht ja noch lange nicht hervor, wo im Filesystem z.B. die Konfigurations- oder Programmdateien des Apachen oder gar des Betriebssystems liegen.

                So long,

                Martin

                1. Hallo Leute,

                  erstaml DANKe für die nette Hilfe.
                  Bei der ganzen Disku. habe ich die Übersicht verloren.
                  Könnt Ihr mir bitte eine genaue Version geben, die jetzt richtig
                  funktioniert. Als Anfanger ist das nicht soooo einfach.

                  cu

                  1. Moin!

                    erstaml DANKe für die nette Hilfe.

                    Dafür ist dieses Forum schließlich da.

                    Bei der ganzen Disku. habe ich die Übersicht verloren.

                    ;-)

                    Könnt Ihr mir bitte eine genaue Version geben, die jetzt richtig
                    funktioniert. Als Anfanger ist das nicht soooo einfach.

                    Unabhängig davon, wie du die Downloads im geschützten Bereich verlinkst, kannst du auf jeden Fall den Code für den Download an sich aus meinem Posting verwenden, den ich hier noch einmal mit Kommentaren versehe:

                      
                    <?php  
                    // In diesem Verzeichnis liegen alle Downloads:  
                    $ordner = '/pfad/zu/meinen/Downloads/';  
                      
                    // Hiermit ist sichergestellt, dass $datei nur noch den Dateinamen  
                    // (inkl. Endung) enthält und „sauber“ ist; $datei enthält vor allem  
                    // auch keine anderen gefährlichen Zeichen wie NULL-Bytes mehr.  
                    $datei  = basename($_GET['dateiname']);  
                      
                    // Wir senden Binärdaten …  
                    header('Content-Type: application/octet-stream');  
                    // … die der Browser bitte unter $datei speichern möge.  
                    header('Content-Disposition: attachment; filename=' . $datei);  
                      
                    // Sende die komplette Datei an den Server:  
                    readfile($ordner . $datei);  
                    ?>  
                    
                    

                    Viele Grüße,
                    Robert

        2. Hi Roland,

          wenn ich die .htaccess-Datei in den Ordner einfüge, auf welche chmod stell ich diesen Ordner dann?

          Die Leserechte müssen so gesetzt sein, dass der PHP Prozess darauf zugreifen kann - mit .htaccess hat das nichts zu tun. Die .htaccess sperrt nur den Zugriff übers Web, mit PHP kannst du alles machen, was du ohne .htaccess vorher auch konntest.

          ich glaube dieser Code müsste den Zweck erfüllen (ich hoffe ich hab keine fehler reingeschrieben, aber bei allg. lesezugriff => 777 und keine htaccess-Datei funktionierts

          777 ist immer die Hammer-Methode - das solltest du wenn irgendwie möglichk nicht verwenden. Meinst sollte z.B. 660 oder so etwas reichen.

          <?PHP

          $application = $_GET['application'];
             $dateiname = $_GET['dateiname'];
             header("Content-type: application/$application");
             header("Content-Disposition: attachment; filename=".$dateiname.".".$application."");
             readfile("../files/$dateiname.$application");
          ?>

            
          VORSICHT!! Damit hast du gerade eine ganz tolle Sicherheitslücke geschaffen! Angenommen du hast eine Datei im Documen Root liegen, die Passwort Dateien für z.B. ein MySQL Verbindung oder so etwas beinhaltet, die Datei heißt z.B. config.php.  
            
          Jetzt rufe ich dein Script einfach mit ?dateiname=../config&application=php auf und schon bekomme ich den Inhalt der Datei zugeschickt und habe deine Passwörter.  
            
          Du musst also vorher zwingend überprüfen, ob die Datei auch im Ordner files liegt und andernfalls den Zugriff verweigern. Das Umwandeln der ../ und ./ ließe sich z.B. prima mit der PHP Funktion [realpath()](http://de3.php.net/manual/en/function.realpath.php) lösen, anschließend noch kontrollieren, ob der Ordner der richtige ist und gut ist - so könnte es z.B. konkret aussehen:  
            
          ~~~php
          $file = $_GET['filename'];  
          $path = "/absoluter/pfad/zum/ordner/files/";  
            
          if(($filepath = realpath($path . $file)) !== false)  
          {  
            if(dirname($filepath) == $path)  
            {  
               // Datei senden  
            }  
          }
          

          Von der Idee her sollte das so in etwa gehen - ich weiß nur z.B. grade nicht genau, ob dirname() den Pfad mit abschließendem Slash oder ohne zurück gibt - wenn ohne, dass würde die 2. Bedingung nicht greifen und müsste noch etwas modifiziert werden.

          MfG, Dennis.

          --
          Mein SelfCode: ie:{ fl:( br:> va:) ls:[ fo:) rl:( n4:# ss:) de:] js:| ch:{ sh:| mo:} zu:|
          .htpasswd Datei mit PHP erzeugen
          "Funktioniert nicht" hat exakt den selben Aussagewert wie "husseldiguggeldu" (Cheatah)
        3. Moin!

          wenn ich die .htaccess-Datei in den Ordner einfüge, auf welche chmod stell ich diesen Ordner dann?

          Ganz normal, Hauptsache, der Apache kann das Verzeichnis lesen, also 755, Standard-Berechtigung für Verzeichnisse (und ausführbare Dateien).

          ich glaube dieser Code müsste den Zweck erfüllen (ich hoffe ich hab keine fehler reingeschrieben, aber bei allg. lesezugriff => 777 und keine htaccess-Datei funktionierts

          Wozu brauchst du hier 777? Du weißt schon, dass das bedeutet, dass _jeder_ in deinem Verzeichnis (fast) alles machen kann, was er will: 777 heißt, dass du (die erste Stelle) Dateien Lesen (4) und Schreiben (+2) kannst sowie das Verzeichnis durchsuchen darfst. Für alle Leute in deiner Gruppe (die zweite Stelle) trifft dies ebenfalls zu, sowie für _jeden_, der einen Benutzeraccount auf deinem Server besitzt bzw. erlangen kann. Mit ein bisschen schlampiger Programmierung hast du bei 777 Ruckzuck ein Upload-Verzeichnis, von dem du vielleicht noch nicht einmal etwas weißt.

          Viele Grüße,
          Robert