Fritz: .htaccess Allow from Namensadresse

Hallo,

Ich möchte den Zugriff auf .zip files in einem Verzeichnis nur dann erlauben, wenn die Dateien per Link von meiner site aufgerufen werden.
Dazu benutze ich folgende .htaccess:

<Files *.zip>
Order deny,allow
Deny from all
Allow from xxx
</Files>

Für xxx darf laut http://de.selfhtml.org/servercgi/server/htaccess.htm#ip_bereiche_namen
stehen:
"In Zeilen, die mit Deny from oder Allow from beginnen, geben Sie eine konkrete IP-Adresse, einen Teil davon, eine Namensadresse oder einen Teil davon an."

Mit der IP scheint dies auch zu klappen. Leider löst dies mein Problem nicht, da die IP meiner site dynamisch vergeben wird.

Also Teil einer Namensadresse:
Allow from .meinedomain.de
funktioniert leider nicht.

Kann mir bitte jemand sagen, was ich falsch mache, oder noch besser, wie ich das richtig mache.
Oder ist mein Ansatz grundsätzlich ungeeignet?

Gruß Fritz

--
ie:( fl:( br:? va:) ls:< fo:| rl:? ss:{ de:> js:| mo:} zu:}
http://webdesign.weisshart.de/
  1. Hi,

    Ich möchte den Zugriff auf .zip files in einem Verzeichnis nur dann erlauben, wenn die Dateien per Link von meiner site aufgerufen werden.

    es gibt keine Methode, das so einzuschränken. Jedenfalls keine sichere.

    <Files *.zip>
    Order deny,allow
    Deny from all
    Allow from xxx
    </Files>

    In diesem Ansatz hast du einen schwerwiegenden gedanklichen Fehler: Es ist ja nicht dein Server, der die Ressource abruft, sondern der Client des Besuchers. Konkret: Wenn ich deine Website aufrufe und dann auf deiner Seite einen Link auf so ein zip-Archiv anklicke, dann sendet ja *mein PC* einen Request an deinen Server. Dein Server kann dann nicht mehr erkennen, ob ich vorher eine Seite deiner Web-Präsenz abgerufen habe oder die URL des zip-Archivs direkt eingegeben habe.

    Mit der IP scheint dies auch zu klappen.

    Das täuscht. Es sei denn, Client (Browser) und Server laufen auf derselben Maschine. Hostest du die Website etwa auf deinem eigenen PC zuhause am DSL-Anschluss?

    Leider löst dies mein Problem nicht, da die IP meiner site dynamisch vergeben wird.

    Das bestärkt mich jedenfalls in dieser Vermutung.

    Kann mir bitte jemand sagen, was ich falsch mache, oder noch besser, wie ich das richtig mache.
    Oder ist mein Ansatz grundsätzlich ungeeignet?

    Ja, leider.
    Du hast nur eine Chance, "berechtigte" Zugriffe nach deiner Definition zu erkennen, und das ist der HTTP-Referer. Das Dumme ist nur, dass diese Angabe alles andere als zuverlässig ist: Die HTTP-Spezifikation schreibt nicht vor, dass überhaupt ein Referer gesendet werden muss, in einigen Browsern kann man ihn abstellen, manche Firewalls, Proxies und Privacy-Tools filtern ihn aus oder schreiben irgendeinen Blödsinn rein.

    Meiner Ansicht nach hast du nur die Möglichkeit, entweder diese Deeplinks zu akzeptieren, oder mit einem Session-Management sicherzustellen, dass nur derjenige die zip-Archive herunterladen darf, wer zuvor deine Seite abgerufen hat.

    So long,
     Martin

    --
    "Drogen machen gleichgültig."
     - "Na und? Mir doch egal."
    1. Hallo,

      In diesem Ansatz hast du einen schwerwiegenden gedanklichen Fehler:

      Ja, das ist mir jetzt auch klar.

      ... oder mit einem Session-Management sicherzustellen, dass nur derjenige die zip-Archive herunterladen darf, wer zuvor deine Seite abgerufen hat.

      Ich versuch' mal, meine Gedanken zu ordnen:
      Um deep links zu unterbinden, müsste ich in jedem Fall zuerst per
      Deny from all
      alle direkten Aufrufe der URL verbieten.
      Dann hat nur noch PHP Zugriff (richtig?)
      Aber wie geht es dann weiter? Wie kann Session Management mir weiterhelfen?

      Gruß Fritz

      --
      ie:( fl:( br:? va:) ls:< fo:| rl:? ss:{ de:> js:| mo:} zu:}
      http://webdesign.weisshart.de/
      1. Hi Fritz,

        Um deep links zu unterbinden, müsste ich in jedem Fall zuerst per
        Deny from all
        alle direkten Aufrufe der URL verbieten.

        Oder, noch schöner (falls dein Provider es dir ermöglicht), die Dateien direkt außerhalb des DocumentRoot speichern.

        Dann hat nur noch PHP Zugriff (richtig?)

        Und Perl, und Python, und jedes andere Programm auf dem Server, welches Leserechte auf die Datei hat. Die Apache-Konfiguration bezieht sich natürlich nur auf Clients, die über HTTP mit dem Apache kommunizieren und diese Ressource abrufen wollen - und dass du dies verbietest reicht in deinem Fall ja auch.

        Aber wie geht es dann weiter? Wie kann Session Management mir weiterhelfen?

        Beispiel:

        -- linkSeite.php --

        <?php  
        [link:http://de3.php.net/manual/en/function.session-start.php@title=session_start]();  
        $_SESSION['hatLinkSeiteGesehen'] = true;  
        ?>
        
        <!DOCTYPE [...]>  
        <!-- HTML-Seite mit Link auf downloadSeite.php -->
        

        -- downloadSeite.php --

        <?php  
        [link:http://de3.php.net/manual/en/function.session-start.php@title=session_start]();  
        if(isset($_SESSION['hatLinkSeiteGesehen']) AND $_SESSION['hatLinkSeiteGesehen'] == true) {  
          [link:http://de3.php.net/manual/en/function.header.php@title=header]('Content-Type: application/zip');  
          [link:http://de3.php.net/manual/en/function.header.php@title=header]('Content-Disposition: attachment;filename=datei.zip');  
          // file_get_contents() soll angeblich schneller sein als readfile()  
          echo [link:http://de3.php.net/manual/en/function.file-get-contents.php@title=file_get_contents]('pfad/zu/datei.zip');  
        }  
        else {  
          echo 'Böser Bub!! Guck dir erst die linkSeite an ;-)';  
        }
        

        Erläuterung:

        Du hast weiterhin deine normale Seite mit dem Link zum Download. Den Download-Link passt du auf ein Download-Script an (also nicht direkt auf die zip-Datei wie bisher). In der Seite mit dem Download-Link speicherst du dann in der Session, dass der Besucher diese Seite besucht hat und im Download-Script prüfst du dann eben diesen Wert aus der Session erneut.

        Viele Grüße,
          ~ Dennis.

        1. Hallo Dennis,

          header('Content-Disposition: attachment;filename=datei.zip');
          echo file_get_contents('pfad/zu/datei.zip');

          Darauf wär ich nie gekommen. Die Kombination von header und echo file_get_contents(...) ... das muss ich mir nochmal in Ruhe anschauen, was da im Einzelnen passiert.

          Jedenfalls hab' ich jetzt genau, was ich suchte, und es funktioniert perfekt.

          Danke schön

          Gruß Fritz

          --
          ie:( fl:( br:? va:) ls:< fo:| rl:? ss:{ de:> js:| mo:} zu:}
          http://webdesign.weisshart.de/
          1. Hallo,

            Hallo Dennis,

            header('Content-Disposition: attachment;filename=datei.zip');
            echo file_get_contents('pfad/zu/datei.zip');

            Darauf wär ich nie gekommen. Die Kombination von header und echo file_get_contents(...) ... das muss ich mir nochmal in Ruhe anschauen, was da im Einzelnen passiert.

            Jedenfalls hab' ich jetzt genau, was ich suchte, und es funktioniert perfekt.

            Danke schön

            Gruß Fritz

            Gruß Fritz

            --
            ie:( fl:( br:? va:) ls:< fo:| rl:? ss:{ de:> js:| mo:} zu:}
            http://webdesign.weisshart.de/
          2. Hallo,

            header('Content-Disposition: attachment;filename=datei.zip');
            echo file_get_contents('pfad/zu/datei.zip');

            Darauf wär ich nie gekommen. Die Kombination von header und echo file_get_contents(...) ... das muss ich mir nochmal in Ruhe anschauen, was da im Einzelnen passiert.

            ja, das solltest du tun. :-)
            Und vielleicht stellst du dann fest, dass die Sequenz

            header('Content-Disposition: attachment;filename=datei.zip');
              readfile('pfad/zu/datei.zip');

            das gleiche leistet, aber noch einfacher aussieht und noch dazu Speicher spart. Denn während die Variante von Dennis erst den gesamten Dateiinhalt in den Arbeitsspeicher lädt (und bei großen Dateien vielleicht daran scheitert, weil PHP z.B. nur 8MB insgesamt bekommt), wird bei readfile() dieser Dateiinhalt einfach nur durchgereicht, ohne ihn zwischenzuspeichern.

            Schönen Abend noch,
             Martin

            --
            Computer lösen für uns Probleme, die wir ohne sie gar nicht hätten.
            1. Hi Martin,

              Denn während [readfile()] erst den gesamten Dateiinhalt in den Arbeitsspeicher lädt [...], wird bei readfile() dieser Dateiinhalt einfach nur durchgereicht, ohne ihn zwischenzuspeichern.

              Ich hatte in der Tat auch erst readfile() da stehen ;-) Hab es dann aber zu echo file_get_contents() umgeändert, da im PHP Manual steht:

              file_get_contents() is the preferred way to read the contents of a file
                into a string. It will use memory mapping techniques if supported by your
                OS to enhance performance.

              Das hört sich ja erst mal recht vernünftig an. Um den Inhalt durchzuschleusen dürfte readfile() eigentlich besser sein, allerdings nur, wenn es PHP-intern auch gescheit programmiert ist - und da hab ich etwas Bedenken ;-) Wie sieht es mit Output-Buffering aus? Sorgt readfile() gezielt für flush() bzw. kann man readfile() dazu bringen dies zu tun? Wie groß sind die Blöcke, in denen readfile() einliest und ausgibt?

              Im Zweifelsfall also lieber selber machen:

              // Datei öffnen  
              $fp = fopen('path/to/file.ext', 'r');  
              // für Lesezugriff sperren  
              flock($fp, LOCK_SH);  
              // solange Ende nicht erreicht  
              while(!feof($fp)) {  
                // 100 kB einlesen und ausgeben  
                echo fread($fp, 102400);  
                // explizit an Client senden  
                flush();  
              }  
              // Datei schließen  
              fclose($fp);
              

              Wäre jetzt nur noch die Frage, welche Größe als Buffer optimal ist... Ich denke 100 KB sind nicht schlecht, wenn 50 Leute gleichzeitig die Datei herunterladen sind knapp 5 MB Arbeitsspeicher belegt, was IHMO akzeptabel ist. Gleichzeitig muss der Server nicht so viele Schleifen durchlaufen, wie er es bei z.B. 10 KB Blöcken machen müsste.

              Eventuell wären auch 500 KB als Buffer noch akzeptabel, dann wären bei 50 gleichzeitigen Downloads allerdings knapp 25 MB Arbeitsspeicher belegt. Muss man sich eben überlegen, wo man Prioritäten setzt ;-)

              Viele Grüße,
                ~ Dennis.

          3. Hallo,

            ... und es funktioniert perfekt.

            ... dachte ich wenigstens, solange, bis ich es erstmals mit dem IE6 versuchte.
            Der IE6 (und _nur_ der!?) lädt eine leere zip herunter - vermutlich findet er einfach die Datei nicht.

            ich hab es sowohl mit http:// versucht, also:

            header('Content-Type: application/zip');
            header('Content-Disposition: attachment;filename=archiv.zip');
            readfile('http://meinedomain.de/subdir/archiv.zip');

            als auch mit Serveradresse:
            ...
            readfile('/home/webxxx/public_html/xxx/subdir/archiv.zip');

            und beide Varianten ebenfalls mit
            echo file_get_contents(...

            Die Pfade stimmen, sowohl Firefox und Opera, als auch der IE7 öffnen die zip korrekt.

            Was auffällt: der download Dialog von IE6 zeigt keine Dateigröße an.
            Dort steht bei "normalen" Downloads:
            Typ: WinZip File, 23,2kB
            mit der Konstruktion per header/readfile aber nur
            Typ: WinZip File

            Nochmal: es dürfte eher nicht an meinem IE6 liegen. Bei einem Link auf das zip Archiv lädt er die Datei korrekt.

            Gruß Fritz

            --
            ie:( fl:( br:? va:) ls:< fo:| rl:? ss:{ de:> js:| mo:} zu:}
            http://webdesign.weisshart.de/
            1. Hallo,

              Es wird immer merkwürdiger:
              Der IE6 kann die so zum download angebotene Datei korrekt speichern, aber _nicht_ direkt öffnen.

              Damit kann _ich_ zwar jetzt umgehen, aber so eine Lösung kann man nicht ernsthaft im Web anbieten. Etwa mit einem Hinweis auf dieses merkwürdige Verhalten: "bitte öffnen Sie die Datei nicht, sondern speichern Sie sofort"?
              Ich würde bei einem solchen Hinweis mehr als misstrauisch, und würde spätestens hier abbrechen.

              Gruß Fritz

              --
              ie:( fl:( br:? va:) ls:< fo:| rl:? ss:{ de:> js:| mo:} zu:}
              http://webdesign.weisshart.de/
  2. Moin Fritz,

    Oder ist mein Ansatz grundsätzlich ungeeignet?

    Leider ja :-)

    Steht Dir PHP zur Verfügung? Und wenn ja kannst Du damit umgehen?

    regds
    Mike©

    --
    Freunde kommen und gehen. Feinde sammeln sich an.