BloodySword: Bilder außerhalb von HTDOCS ablegen und per fpassthrough per PHP

Hallo allerseits.

Ich habe folgende Idee:

Ich habe ein sehr großes Bilderarchiv, welches im Moment noch in HTDOCS liegt. Wenn ein
User also nicht in meinem Communitysystem registriert ist, den Pfad aber kennt, kann er jedes Bild problemlos im Browser einsehen. Dem möchte ich ein Riegel vorschieben.

Eine Lösung habe ich mir bereits überlegt, weiß aber nicht ob sich das so einfach bewerkstelligen lässt:

Ich lege die Bilder in einem Ordner außerhalb von HTDOCS ab und greife mit PHP darauf zu, sobald ein Bild geladen werden muss und gebe das Bild per fpassthru() aus.

Zurzeit sieht es so aus, klappt wunderbar:

  // Session starten  
  session_start();  
  
  include ("includes/sqlconnect.php"); //Mit Datenbank verbinden. Wird in $db geschrieben  
  include ("includes/checkuser.php"); //Prüfen ob die Session noch gültig ist  
  
  
   /*-------------------------------------------*\  
  |      Bild anhand ID ausgeben, Miniscript     |  
  \*-------------------------------------------*/  
  
  if (isset($_GET['user_pic']) || isset($_GET['user_thumb']) || isset($_GET['pic_big'])  
   || isset($_GET['pic_small']) || isset($_GET['pic_thumb']) || isset($_GET['pic_mt'])) {  
    $db->close(); unset($db); //Wir brauchen hier keine Datenbank ^^  
  
    $galery_base="../../userdata/gallery/";  
  	if(isset($_GET['pic_big']))  
      $filename="{$galery_base}{$_GET['pic_big']}b.jpg";  
    elseif (isset($_GET['pic_small']))  
      $filename="{$galery_base}{$_GET['pic_small']}s.jpg";  
    elseif (isset($_GET['pic_thumb']))  
      $filename="{$galery_base}{$_GET['pic_thumb']}t.jpg";  
    elseif (isset($_GET['pic_mt']))  
      $filename="{$galery_base}{$_GET['pic_mt']}mt.jpg";  
    elseif (isset($_GET['user_pic']))  
      $filename="{$galery_base}user{$_GET['user_pic']}.jpg";  
    elseif (isset($_GET['user_thumb']))  
      $filename="{$galery_base}user{$_GET['user_thumb']}th.jpg";  
  
    $img_base="images/gallery/";  
    if(file_exists($filename)===false) {  
      if(isset($_GET['user_pic']))  
        $filename="{$img_base}noprofilepic.png";  
      elseif (isset($_GET['user_thumb']))  
        $filename="{$img_base}noprofilepic96.png";  
      elseif (isset($_GET['pic_big']) || isset($_GET['pic_small']) ||  
              isset($_GET['pic_thumb']) || isset($_GET['pic_mt']))  
        $filename="{$img_base}nopic.png";  
    }  
  
    $currdate=date("r");  
    $fildate=date("r",filemtime($filename));  
  
    $imginf=getimagesize($filename);  
    $fimg=fopen($filename, "rb");  
    if ($imginf && $fimg) {  
      header("Date: {$currdate}");  
      header("Last-Modified: {$fildate}");  
      header("Content-Type: {$imginf['mime']}");  
      header("Cache-Control: public");  
      fpassthru($fimg); fclose($fimg); exit;  
    } else {  
      echo "Error opening picture!"; exit;  
    }  
  }  
  
//(... weiterer Code der gesamten Galerie ...)

Nun möchte ich den Ordner "userdata" außerhalb von HTDOCS verschieben.
Ist das ohne Weiteres möglich? Was muss ich einstellen, damit PHP auf diese
Dateien zugreifen kann?

Zurzeit läuft das Projekt noch lokal auf meinem Laptop in XAMPPLITE.

Vielen Dank im Voraus! :)

  1. Hi!

    Nun möchte ich den Ordner "userdata" außerhalb von HTDOCS verschieben.
    Ist das ohne Weiteres möglich?

    Dazu muss der Hoster mitspielen. Schau mal nach nebenan.

    Was muss ich einstellen, damit PHP auf diese Dateien zugreifen kann?

    Im Allgemeinen nichts weiter. PHP kann auf das Dateisystem entsprechend der Rechte, unter dem es läuft, zugreifen. Weitere Einschränkungen kann es über open_basedir geben. Ein Webserver beschränkt die Requestwünsche auf Dinge innerhalb des DocumentRoots, PHP ist aber nicht der Webserver und unterliegt diesbezüglich nicht dessen Konfiguration.

    Lo!

    1. Dazu muss der Hoster mitspielen. Schau mal nach nebenan.

      Session-Probleme hab ich nicht, weiß nicht worauf du da hinaus willst ^^.

      Im Allgemeinen nichts weiter. PHP kann auf das Dateisystem entsprechend der Rechte, unter dem es läuft, zugreifen. Weitere Einschränkungen kann es über open_basedir geben. Ein Webserver beschränkt die Requestwünsche auf Dinge innerhalb des DocumentRoots, PHP ist aber nicht der Webserver und unterliegt diesbezüglich nicht dessen Konfiguration.

      Lo!

      Ich hab's einfach mal in meinem XAMPPLITE ausprobiert... Funzt ^^.

      Aber das ist ja jetzt hier Windows (Vista). Wenn mein Projekt stabil läuft
      und alle Tests überstanden sind, gehe dann online. Da muss ich mich dann beim
      Hoster informieren. Wie müssen bei einem Linuxsystem die Rechte eingestellt sein?

      Sagen wir das Verzeichnis "userdata" ist in dem Verzeichnis wie htdocs,
      also liegen nebeneinander in einem Verzeichnis. Welche Rechtevergabe muss
      das Verzeichnis "userdata" bekommen, damit PHP vom Apache drauf zugreifen kann?

      1. Hi!

        Dazu muss der Hoster mitspielen. Schau mal nach nebenan.
        Session-Probleme hab ich nicht, weiß nicht worauf du da hinaus willst ^^.

        Nein, aber du hast ein Problem, das sich mit der selben Verzeichnisstruktur und DocumentRoot-Konfiguration wie für das dortige Session-Problem lösen lässt.

        Wenn mein Projekt stabil läuft und alle Tests überstanden sind, gehe dann online. Da muss ich mich dann beim Hoster informieren. Wie müssen bei einem Linuxsystem die Rechte eingestellt sein?

        So dass die Kennung, unter der dein PHP läuft lesend darauf zugreifen kann. Alle anderen müssen nicht. Ausnahme ist der Benutzer, mit dem du selbst die Verzeichnispflege vornimmst.

        Sagen wir das Verzeichnis "userdata" ist in dem Verzeichnis wie htdocs, also liegen nebeneinander in einem Verzeichnis.

        Damit hast du auf den ersten Blick so eine Struktur wie beim Sessiondaten-Problem. Das ist gut so, aber nur dann vollständig, wenn beide Verzeichnisse nicht durch eine andere Konfiguration innerhalb des DocumentRoot eines anderen (virtuellen) Hosts liegen.

        Beispiel 1&1. Dort bekommt man als Hosting-Kunde eine Inklusivdomain (s{ziffernkolonne}.online.de), die auf das Kundenwurzelverzeichnis zeigt. Legt man nun ein Unterverzeichnis "meine" an und konfiguriert sich seine Domain meine.example.com so, dass das DocumentRoot auf /kundenwurzel/meine verweist, sowie noch ein zweites wie /kundenwurzel/geheim, so hat man immer noch keinen ungeschützten Platz, weil die inkluve s-Domain weiterhin "meine" und "geheim" beinhaltet. Deswegen muss man auch noch diese Inklusivdomain auf irgendein unschädliches Unterverzeichnis umbiegen.

        Welche Rechtevergabe muss das Verzeichnis "userdata" bekommen, damit PHP vom Apache drauf zugreifen kann?

        rx für das Verzeichnis, r für die Dateien, und das für die Kennung, unter der das PHP läuft.

        Lo!

        1. Danke für die Hinweise, bringt mich echt weiter. :) Aber ich hab noch ein Plan B:

          Falls das so, wie ich das jetzt vor habe nicht klappen sollte, ginge das auch zuverlässig und Hacksicher mit .htaccess?

          Sagen wir die Ordnerstruktur ist so:

          /htdocs
          /htdocs/community
          /htdocs/userdata
          /htdocs/userdata/gallery

          Wenn ich in /htdocs/userdata ein .htaccess packe, welches das Anzeigen und Listen des Ordners unterbindet, sowie das direkte Aufrufen von Dateien, bin
          ich dann 100%ig sicher?

          BTW: Was muss dann in der .htaccess stehen?

          lg

          1. Hi!

            Falls das so, wie ich das jetzt vor habe nicht klappen sollte, ginge das auch zuverlässig und Hacksicher mit .htaccess?

            Die Zuverlässigkeit steht und fällt einerseits mit der Integrität der .htaccess (darf nicht geändert, gelöscht oder überschrieben werden können), andererseits mit der grundlegenden Apachekonfiguration. In der kann das Berücksichtigen der komplette .htaccess oder bestimmter Direktivengruppen geregelt werden.

            Es gibt abseits einer Apache-Konfigurationsänderung mindestens drei Möglichkeiten, wie eine .htaccess ungewollt beinflusst werden kann.
            Jemandem muss gelingen, eine Datei gleichen Namens in das Verzeichnis zu legen. Ein Kopierscript ohne ausreichende Prüfung und/oder Schreibrechte auf der .htaccess genügen.
            Jemand editieren den Dateiinhalt, wofür er Shellzugang benötigt oder ein Script missbrauchen kann, das für das Editieren einer anderen Datei vorgesehen ist und überredet werden kann, eine andere Datei zu bearbeiten. Wobei auch hier wieder Schreibrechte benötigt werden.
            Jemand löscht die .htaccess, wofür er Schreibrechte im Verzeichnis benötigt, denn Löschen ist eine Schreiboperation in einem Verzeichnis. Die einzelnen Dateirechte interessieren dabei nicht.

            Eine nur lesbare .htaccess wäre eine Notlösung. Berechtigungen können normalerweise mit FTP-Clients gesetzt werden.

            BTW: Was muss dann in der .htaccess stehen?

            deny from all

            Das bezieht sich ausschließlich auf die Requests über den Webserver, nicht aber auf Dateisystemzugriffe aus PHP heraus.

            Lo!

            1. Nabend!

              Die Zuverlässigkeit steht und fällt einerseits mit der Integrität der .htaccess (darf nicht geändert, gelöscht oder überschrieben werden können), andererseits mit der grundlegenden Apachekonfiguration. In der kann das Berücksichtigen der komplette .htaccess oder bestimmter Direktivengruppen geregelt werden.

              Das wird ja über den Hoster geregelt. Da heißt es: Nachfragen.

              Es gibt abseits einer Apache-Konfigurationsänderung mindestens drei Möglichkeiten, wie eine .htaccess ungewollt beinflusst werden kann.
              Jemandem muss gelingen, eine Datei gleichen Namens in das Verzeichnis zu legen. Ein Kopierscript ohne ausreichende Prüfung und/oder Schreibrechte auf der .htaccess genügen.

              Gibt es bei unserem System nicht. Wir haben strikt darauf geachtet, dass
              die Scripts keine Lücken haben mit denen man unbefugt irgendetwas ändern
              könnte. Es gibt ein Script, welches ein Profilbild hochlädt. Allerdings
              ist dieses soweit abgesichert, dass sich 1. nur Bilder hochladen lassen
              und 2. wird das Bild anschließend verkleinert. Das Bedeutet, das Script
              würde sowieso abbrechen, da eine Textdatei nicht als Bild geöffnet werden
              kann.

              Jemand editieren den Dateiinhalt, wofür er Shellzugang benötigt oder ein Script missbrauchen kann, das für das Editieren einer anderen Datei vorgesehen ist und überredet werden kann, eine andere Datei zu bearbeiten. Wobei auch hier wieder Schreibrechte benötigt werden.

              Bei uns wird alles über MySQL geregelt, es wird keine einzige Datei
              bearbeitet. Also auch Glück gehabt ^^.

              Jemand löscht die .htaccess, wofür er Schreibrechte im Verzeichnis benötigt, denn Löschen ist eine Schreiboperation in einem Verzeichnis. Die einzelnen Dateirechte interessieren dabei nicht.

              Dazu müsste er den FTP-Zugang hacken...

              Eine nur lesbare .htaccess wäre eine Notlösung. Berechtigungen können normalerweise mit FTP-Clients gesetzt werden.

              Wieso eine Notlösung? Ist der Weg mit dem Ausschließen eines Verzeichnisses
              aus htdocs die bessere Wahl?

              BTW: Was muss dann in der .htaccess stehen?

              deny from all

              Das bezieht sich ausschließlich auf die Requests über den Webserver, nicht aber auf Dateisystemzugriffe aus PHP heraus.

              Lo!

              Danke, das hilft mir schon weiter :).

              Am Besten sollte ich diese .htaccess Datei in den Ordnern packen, in denen
              sich die ganzen PHP und INC-Dateien befinden.

              1. Hi!

                Eine nur lesbare .htaccess wäre eine Notlösung. Berechtigungen können normalerweise mit FTP-Clients gesetzt werden.
                Wieso eine Notlösung? Ist der Weg mit dem Ausschließen eines Verzeichnisses aus htdocs die bessere Wahl?

                Ja, so eine .htaccess ist beim Verzeichnisaufräumen auch mal schnell gelöscht, wenn man nicht aufpasst. Eine DocumentRoot-Änderung wird irgendwo anders durchgeführt und das passiert seltener aus Versehen.

                Lo!

                1. Ja, so eine .htaccess ist beim Verzeichnisaufräumen auch mal schnell gelöscht, wenn man nicht aufpasst.

                  Schreibschutz auch für root rein ;).

                  lg

                  1. Hi!

                    Ja, so eine .htaccess ist beim Verzeichnisaufräumen auch mal schnell gelöscht, wenn man nicht aufpasst.
                    Schreibschutz auch für root rein ;).

                    Das nützt dir nichts. Löschen ist eine Schreiboperation im Verzeichnis. Du brauchst Schreibrechte für das Verzeichnis, um dort Dateien löschen zu können, und das schließt die .htaccess mit ein. Es geht problemlos, Dateien zu löschen, zu denen du keine Rechte hast, solange du Schreibrechte für das Verzeichnis besitzt.

                    Lo!

                    1. Ich könnte aber auch in der sqlconnect.php eine Codezeile machen, die Prüft ob alle .htaccess noch da sind und der Inhalt okay ist. Wenn nicht, werden die neu erstellt. Sollte sicher gehen ^^.

                      1. Hi!

                        Ich könnte aber auch in der sqlconnect.php eine Codezeile machen, die Prüft ob alle .htaccess noch da sind und der Inhalt okay ist. Wenn nicht, werden die neu erstellt. Sollte sicher gehen ^^.

                        Das setzt voraus, dass PHP Schreibzugriff für dieses Verzeichnis bekommt. Wenn es den sowieso schon hat, dann ist das zumindest nicht unsicherer als auch sonst. Aber angenommen, die .htaccess ist weg, dann greift der Apache an PHP vorbei auf die Dateien zu. Und dein PHP steht daneben und bekommt davon nicht mal was mit.

                        Lo!

                        1. Hi!

                          Ich könnte aber auch in der sqlconnect.php eine Codezeile machen, die Prüft ob alle .htaccess noch da sind und der Inhalt okay ist. Wenn nicht, werden die neu erstellt. Sollte sicher gehen ^^.

                          Das setzt voraus, dass PHP Schreibzugriff für dieses Verzeichnis bekommt. Wenn es den sowieso schon hat, dann ist das zumindest nicht unsicherer als auch sonst. Aber angenommen, die .htaccess ist weg, dann greift der Apache an PHP vorbei auf die Dateien zu. Und dein PHP steht daneben und bekommt davon nicht mal was mit.

                          Lo!

                          sqlconnect ist in fast jeder php included. Ausgenommen so kleine Scripte, die
                          keine Anmeldung benötigen. Ich habe nämlich zusätzlich zu dem
                          PHP-Sessionsystem in der Datenbank eine Tabelle um die online User
                          herauszufinden... Deshalb wird mit jedem Klick eines Users die sqlconnect ausgeführt.

                          Dort kommt folgende Zeilen als Beispiel:

                          if(file_exist("includes/.htaccess")===false ||  
                             read_file("includes/.htaccess")=="deny from all") {  
                            //.htaccess neu erstellen  
                          }
                          

                          Warum sollte das nicht funktionieren? Wenn viele User online sind, ist die
                          Zeit, die ein Hacker dann hätte so kurz, dass es nicht mehr unsicher ist.

                          1. Hi!

                            sqlconnect ist in fast jeder php included. [...] Deshalb wird mit jedem Klick eines Users die sqlconnect ausgeführt.

                            Nein, sie wird nur bei jedem Request berücksichtigt, der an PHP weitergereicht wird. Dazu musst du deinen Apachen so konfigurieren, dass er das wirklich bei jedem Request macht, zumindest für das fragliche Verzeichnis. Es nützt ja nichts, wenn das für irgendwelche anderen Request geregelt ist. Wenn diese (zu verkehrsschwachen Zeiten) nicht vorkommen, greife ich munter auf die ungeschützten Dateien zu.

                            Warum sollte das nicht funktionieren? Wenn viele User online sind, ist die Zeit, die ein Hacker dann hätte so kurz, dass es nicht mehr unsicher ist.

                            Sicherheit hat nichts mit Wahrscheinlichkeit zu tun. Die Kuh ertrinkt auch in einem durchschnittlich 1 Meter tiefen See.

                            Lo!

                          2. Hi,

                            Dort kommt folgende Zeilen als Beispiel:

                            if(file_exist("includes/.htaccess")===false ||

                            read_file("includes/.htaccess")=="deny from all") {
                              //.htaccess neu erstellen
                            }

                            
                            >   
                            > Warum sollte das nicht funktionieren? Wenn viele User online sind, ist die  
                            > Zeit, die ein Hacker dann hätte so kurz, dass es nicht mehr unsicher ist.  
                              
                            Wenn der Hacker auf deinem Server liegende Dateien manipulieren kann - wieso sollte er dann ausgerechnet diesen Code in deinen PHP-Scripten unberührt lassen?  
                              
                            MfG ChrisB  
                              
                            
                            -- 
                            “Whoever best describes the problem is the person most likely to solve the problem.” [Dan Roam]