Ankündigung

Einklappen
Keine Ankündigung bisher.

Zugriffskontrolle auf Dateien

Einklappen

Neue Werbung 2019

Einklappen
X
  • Filter
  • Zeit
  • Anzeigen
Alles löschen
neue Beiträge

  • Zugriffskontrolle auf Dateien

    Hallo werte PHP-Gemeinde,

    bin seit längerem mal wieder dabei, ein Projekt mit PHP umzusetzen und möchte mich hiermit in die Reihe der Fragesteller, die nachgrübeln, wie sie Dateien von unautorisiertem Zugriff durch nichtangemeldte Benutzer schützen können, einreihen.

    Ich habe mittlerweile recht viele Beiträge gelesen aber wohl nicht die richtigen Stichwörter benutzt und viel Halbgares gefunden.

    Zur Aufgabe:
    Auf unserer Web Plattform existieren Benutzer, die verschiedenen Rollen angehören können. Je nach Rolle soll eine Webseite x der Plattform mit allen dazugehörigen Bilddaten und Videos, mit einem Teil der Bilddaten und Videos oder gänzlich ohne Bilddaten und Videos angezeigt werden. Auch per Direktlink auf eine Ressource muss sichergestellt sein, dass ein Benutzer nicht mehr zu sehen bekommt, als seine Rolle hergibt.

    Lösungsansatz?
    Der Ansatz den ich aus dem bisher gelesenen konstruiert habe ist folgender:
    - Sensible Dateien werden in ein Verzeichnis ausserhalb der Webroot abgelegt.

    Damit hört es auch schon auf, wie geht es nun weiter? Müsste ich das Verzeichnis je nach Authentifizierungsresultat dynamisch in die Webroot einbinden? Ich möchte vermeiden, die Dateien irgendwie durch den PHP Thread zu schaufeln. Gibt es Webserver, die per durch PHP übergebenen Schalter oder so etwas dynamisch ein virtuelles Verzeichnis mit den zur Rolle passenden Dateien befüllt im Webroot präsentieren?

    Wie habt ihr die Zugriffskontrolle gelöst? Könnt ihr weiterführende Links empfehlen?

    Vielen Dank,
    Bergtroll

  • #2
    Direktlinks verbietest du in der .htaccess.

    Alle Links auf Resourcen werden durch Scripte geschleust, die eine Zugriffsberechtigung überprüfen...

    hoffe, das hilft schonmal
    Über 90% aller Gewaltverbrechen passieren innerhalb von 24 Stunden nach dem Konsum von Brot.

    Kommentar


    • #3
      Hi lstegelitz,

      danke für die schnelle Rückmeldung, ich hatte die bisherigen Texte so verstanden, dass ich .htaccess nicht brauche, sofern alle wichtigen Daten ohnehin ausserhalb der Webroot liegen?

      @Links durchschleusen: Ich kann für jede dieser ausserhalb der Webroot liegenden Dateien eindeutig prüfen, ob der derzeitige Nutzer die Rechte hat, diese anzuzeigen. Falls nicht soll stattdessen eine Surrogatdatei mit dem Hinweis auf ungenügende Rechte genutzt werden.

      Aber ich frage mich nun, wie das auf performante Art geschehen soll, weil ja ein Link im HTML Document, der über die Webroot hinauszeigt, natürlich ins Leere läuft. Die Dateien sollen nicht zum download angeboten sondern in der WEbseite eingebunden werden. Müsste ich für jeden Aufruf jetzt also ein temporäres Verzeichnis unterhalb der Webroot erzeugen, in welches ich die betreffenden Dateien kopiere? Aber selbst dann wären diese für eine gewisse Zeit von aussen direkt sichtbar?

      Kommentar


      • #4
        Zitat von Bergtroll Beitrag anzeigen
        ich hatte die bisherigen Texte so verstanden, dass ich .htaccess nicht brauche, sofern alle wichtigen Daten ohnehin ausserhalb der Webroot liegen?
        Natürlich nicht.

        Die Dateien sollen nicht zum download angeboten sondern in der WEbseite eingebunden werden. Müsste ich für jeden Aufruf jetzt also ein temporäres Verzeichnis unterhalb der Webroot erzeugen, in welches ich die betreffenden Dateien kopiere?
        Oder bspw. einen symbolischen Link innerhalb des Doc_Roots setzen.

        Aber selbst dann wären diese für eine gewisse Zeit von aussen direkt sichtbar?
        Wenn du willst, dass der Client die Ressourcen ganz normal und direkt über HTTP anfordert - dann willst du auch, dass sie "von aussen sichtbar" sind.
        Wenn das nicht ist, was du willst - dann musst du dir erst mal überlegen, was du stattdessen willst.

        Die angesprochene Möglichkeit, die Daten über ein Script durchzuschleusen, welches bei jedem Zugriff zunächst die Berechtigung prüft, ist eine oft genutzte Möglichkeit - natürlich nicht die performanteste.

        Gibt es Webserver, die per durch PHP übergebenen Schalter oder so etwas dynamisch ein virtuelles Verzeichnis mit den zur Rolle passenden Dateien befüllt im Webroot präsentieren?
        Mit den Default-Möglichkeiten eines Apache-Webservers sieht es da eher schlecht aus.
        Natürlich kannst du dir selbst ein Apache-Modul schreiben, das sich in das Request-Handling des Webservers einklinkt und irgendwie einen Wert von PHP übergeben bekommt oder anderweitig die Berechtigung prüft (bspw. Cookie). Aber das wirst du dann nur auf einem eigenen Server laufen lassen können, und nicht in einer shared hosting-Umgebung.

        Der Artikel Secure Downloads with apache + mod_rewrite beschreibt einen Lösungsweg, um den zeitlich begrenzten Download einer Ressource durch einen Benutzer nach Authentifizierung mittels mod_rewrite und Symlinks umzusetzen. (Zwar in Python geschrieben, aber das ist ja simpel adaptierbar.)


        Wenn du in der Wahl des Webservers flexibel bist - für Lighttpd gibt es bspw. das im Artikel ebenfalls erwähnte mod_secdownload, mit dem sowas in der Art wohl möglich sein dürfte.
        [SIZE="1"]RGB is totally confusing - I mean, at least #C0FFEE should be brown, right?[/SIZE]

        Kommentar


        • #5
          Korrekt. Ausserhalb des Webroot brauchts kein .htaccess

          Ein Script kann die Dateien auch "ausliefern".. Sicher steigt die Performance dadurch nicht, da ja zum einen die Sicherheitschecks gemacht werden, zum anderen die Datei gelesen & ausgegeben werden muss.

          Beispiel:

          <img src="getpic.php?id=123" />

          getpic.php
          PHP-Code:
          if ($_GET['id'] == '123') {
             
          readfile(<some file associated wid 123>);
             exit;
          }
          die(
          'no access!'); 
          Du hast demnach keine Links auf die Datei selber, sondern nur noch den Umweg durch das Script.

          Alternativ kannst du dir auch mit mod_rewrite alle Aufrufe auf bestimmte Endungen (.gif, .jpg, .pdf) an eine bestimmte PHP Datei umrouten und dann anhand des Dateinamens das richtige Bild suchen... so kannst du zumindest normale Dateinamen verwenden in den Links.
          Über 90% aller Gewaltverbrechen passieren innerhalb von 24 Stunden nach dem Konsum von Brot.

          Kommentar


          • #6
            Mit Bordmitteln lässt sich das beim Apache durchaus realisieren - mod_rewrite ist nahezu immer verfügbar.
            Das Ganze über eine einfache Perl-RewriteMap (oder auch PHP, Ruby, Whatever) und das läuft.
            Hat einer meiner Kunden für Downloads (über einen internen Proxy) im Einsatz - klappt wunderbar inkl. Beschränkung auf ANzahl Downloads, max. Dauer etc.
            Ist auf jeden Fall deutlich performanter, als ganze Dateien durch irgendwelche Scriptsprachen zu schleusen, weil hier lediglich eine Abfrage gegen die RewriteMap erledigt wird, welche der Apache dann auch noch cached.
            VokeIT GmbH & Co. KG - VokeIT-oss @ github

            Kommentar


            • #7
              Hey, vielen Dank schonmal für eure Rückmeldung

              Wenn du willst, dass der Client die Ressourcen ganz normal und direkt über HTTP anfordert - dann willst du auch, dass sie "von aussen sichtbar" sind.
              Wenn das nicht ist, was du willst - dann musst du dir erst mal überlegen, was du stattdessen willst.
              Da habe ich mich wohl nicht genau genug ausgedrückt. Die Dateien sollen natürlich schon normal von aussen sichtbar sein, aber eben nur für die (zeitlich begrenzten) Sessions, für welche die Sicherheitsprüfung erfolgreich durchgeführt wurde.

              Ich bin deshalb am überlegen, ob es irgendwie möglich ist anhand einer session variable unter dem nach aussen hin gleichen path (z.b. ./images/*) nutzerrechteabhängig intern unterschiedliche directories von ausserhalb der Webroot anzubieten. Der jeweilige Nutzer sollte von dieser Variabilität aber nichts mitbekommen sondern jeweils immer nur das zu seiner Rolle passende Verzeichnis präsentiert bekommen. Dann könnte der Check darauf reduziert werden, dass passende verzeichnis auszuwählen und z.B. den Server anzuweisen, für dieses so zu tun, als wäre es das (./images/*). Speicherplatz ist nicht das Problem, es kann für jede Rolle ein eigenes Verzeichnis aller Grafiken der Webseite mit entsprechender Konfiguration erstellt werden. Ich weiß nur nicht, wie man seinem Server mitteilt, sich auf diese Art zu verhalten.

              Ein Beispiel:
              PHP-Code:
              /out-of-webroot/anonym/userlogo.png (anonymisiert)
              /
              out-of-webroot/anonym/userimage.png (anonymisiert)

              /
              out-of-webroot/registered/userlogo.png (normal sichtbar)
              /
              out-of-webroot/registered/userimage.png (anonymisiert)

              /
              out-of-webroot/premium/userlogo.png (normal sichtbar)
              /
              out-of-webroot/premium/userimage.png (normal sichtbar
              Je nach Rolle (anonym, registered, premium) liefert der Server für die Abfrage des Verzeichnis webroot/images entweder /out-of-webroot/anonym, /out-of-webroot/registered oder /out-of-webroot/premium.

              Servertechnisch muss es übrigens nicht der apache sein, auch lighttpd oder alles andere, das mit php 5.3+, php_pdo und postgresql rennt, wir haben einen dedicated server.

              Ein Script kann die Dateien auch "ausliefern".. Sicher steigt die Performance dadurch nicht, da ja zum einen die Sicherheitschecks gemacht werden, zum anderen die Datei gelesen & ausgegeben werden muss.

              Beispiel:

              <img src="getpic.php?id=123" />
              Hmm... wo landet denn das image dann? Liegt es für den aufruf in irgendeinem flüchtigen Zwischenspeicher? Wird es dem Browser encodiert übertragen und userseitig zusammengesetzt? Können alle Browser das resultat anzeigen?

              Mit Bordmitteln lässt sich das beim Apache durchaus realisieren - mod_rewrite ist nahezu immer verfügbar.
              Das Ganze über eine einfache Perl-RewriteMap (oder auch PHP, Ruby, Whatever) und das läuft.
              Eventuell ist es das was ich suche, ohne dass ich es bisher weiß, werde das gerade mal nachlesen

              Kommentar


              • #8
                Sodalla, ich habe gestern mal ordentlich Doku gewälzt und eine Lösungsansatz für meine Wünsche. Wäre schön, wenn ihr mir sagt, was ihr davon haltet und was daran potentiell schlecht sein könnte. Außerdem habe ich noch ein paar Probleme, bei denen Hilfe auch nett sein könnte.

                Fürs Schema bitte das angehängte Bild anschauen (die Pdf war mit 27kb leider zu groß zum anhängen). Die Idee ist folgende (Nummern sind im Bild veranschaulicht):

                ERKLÄRUNG
                1.:
                /app/images sei ein beliebiges Verzeichnis (z.B. Userbilder) einer Applikation.

                Daneben existiert für jede zu unterscheidende Nutzerrolle der Webapplikation eine eigene Alias, neben denen im Beispiel wären beliebige weitere denkbar:
                /files/anon für die Rolle anonymous
                /files/user für die Rolle user
                /files/prem für die Rolle premium

                2.:
                Die Aliase für alle Rollen aus anonym werden standardmäßig allesamt auf das Verzeichnis für die anonyme Nutzerrolle umgeschrieben. Wenn eine Anfrage hingegen von /app/images aus auf ein nicht anonymes Alias umgebogen wurde, dann soll keine Weiterleitung erfolgen.

                3.:
                Per default werden alle Anfragen an /app/images auf ein PHP script umgeschrieben, dass anhand der angefragten Datei und der aktuellen nutzerrolle die Variable für die RewriteMap in Schritt 4 setzt. Danach sollte das Script zurück zur ursprünglichen Anfrage geben.

                4.:
                In /app/images selbst existiert eine RewriteMap, für welche die nun tatsächlich zu verwendene RewriteRule anhand einer von PHP gesetzten Variable bestimmt wird. Anhand dieser wird in Punkt 5) auf ein Verzeichnis verwiesen. Außerdem wird dann dieser Stelle eine Environment Variable gesetzt, die das im Zielordner definierte Default Rewriting auf den anonymen Ordner verhindert.

                Soweit die Idee, jetzt meine FRAGEN:
                zu 2.:
                Man müsste die Herkunft der Anfrage irgendwie unmanipulierbar überprüfen. Die essentielle Frage wäre hier, ob die z.B. durch "'env|E=VAR:VAL' (set environment variable)" gesetzten internen Variablen von aussen nicht unmanipulierbar sind und auch in der nächsten htaccess Datei im Zielordner verfügbar bleiben.

                zu 3.:
                Ich habe leider die RewriteMap noch nicht ganz gerafft. Wie könnte ich aus PHP heraus die richtige Variable setzen und die kontrolle wieder an den apachen zurückgeben?

                Allgemein
                Momentan teste auf Xampp unter windows. Ich möchte eigentlich nicht, dass der User die Rewrites mitbekommt. Normalerweise sollten das Rewrite durch mod_rewrite doch invisible sein solange man nicht das [R] flag setzt, oder? Irgendwie zeigt er bei mir aber immer die umgeschriebene URL an. Gibts da irgendein verstecktes Default? Oder was anderes? Finde da echt garnix...

                Macht der Ansatz Sinn? Overkill? Unsicher?

                Viele Grüße,
                Bergtroll
                Angehängte Dateien

                Kommentar


                • #9
                  Irgendwie war das angehängte Bild nicht sichtbar...
                  Angehängte Dateien

                  Kommentar


                  • #10
                    Das wird so vermutlich nicht funktionieren, insbesondere das Apache -> PHP -> Apache geht nicht.
                    Ich setze für sowas einen zweiten, nur intern erreichbaren VHost ein, auf den ich per Proxy-Rewrite zugreife.
                    /files/foobar.jpg -> RewriteMap: erlaubt ja/nein -> RewriteRule zum internen VHost per Proxy ([P] bei RewriteRule)
                    VokeIT GmbH & Co. KG - VokeIT-oss @ github

                    Kommentar


                    • #11
                      pheew.... das klingt nicht unkompliziert, ich glaube, dann habe ich heute noch mal ne Menge zu tun. Kannst du mir irgendwie ein Konfigurationsbeispiel oder Tutorial oder so etwas empfehlen?

                      Kommentar


                      • #12
                        Das klingt nur kompliziert.
                        Den internen VHost legst du an wie jeden anderen auch, einzige Ausnahme: er lauscht nur auf 127.0.0.1
                        Den Docroot legst du dann eben in ein Verzeichnis, in dem die ganzen zu schützenden Dateien liegen, das sollte halt von keinem anderen öffentlichen VHost aus erreichbar sein.
                        Und dann halt ganz normal die RewriteRule, z.B. so:
                        Code:
                        RewriteRule    ^(.*)  http://internal-vhost/%{ENV:REQUESTED_DOWNLOAD_FILE}       [P,L]
                        Im Beispiel nutze ich halt ENV-Vars, die von der RewriteMap gefüllt werden, sind hier einige vorgeschaltete Rules drin, die will ich nicht alle posten.
                        VokeIT GmbH & Co. KG - VokeIT-oss @ github

                        Kommentar


                        • #13
                          Hello again,
                          erstmal danke für deinen Hinweis, ich glaube, ich bin schon einen Schritt weiter, die Bilder werden über so einen Backend Proxy geladen, was schonmal gut ist. Aber was die Verknüpfung von PHP mit dieser RewriteMap angeht, da bin ich leider immer noch auf dem Holzweg. Ich würde halt jetzt gerne anhand der User Rolle sagen, auf welches Verzeichnis im Proxyserver zugegriffen werden soll. Gibt es da noch nen Tipp für mich?

                          Kommentar


                          • #14
                            Ganz einfach - du hängst an die Bild-URL die Session-ID an.
                            In der RewriteMap hast du Zugriff auf den Query-String -> Session starten, checken und entsprechend einen Status zurückgeben.

                            Grob umrissen sieht die .htaccess bei mir so aus:
                            RewriteCond $input gegen RewriteMap
                            RewriteRule zum setzen der Env-Vars
                            RewriteRule(s) zum Weiterleiten, wenn der "falsche" Status zurückkommt
                            RewriteRule auf den Proxy

                            Das war's eigentlich auch schon.


                            // Tante Edit:
                            Gut, ich hab jetzt doch mal die .htaccess rausgesucht und dir ein Beispiel gebastelt.
                            Ist nicht perfekt, du solltest aber erkennen, was du wo machen musst.
                            Code:
                            # Check if we have a download link and match it against the RewriteMap
                            RewriteCond       ${mymap:%{REQUEST_URI}}                         (.+)                                                                    [NC]
                            RewriteRule       ^(.*)$                                          -                                                                       [E=RETURN_VALUE:%1]
                            
                            # Set the environmental variable for the download file
                            RewriteCond       %{ENV:RETURN_VALUE}                             ^valid\|(.+)$                                                           [NC]
                            RewriteRule       ^(.*)$                                          -                                                                       [E=LOAD_FROM_FOLDER:%1]
                            
                            # File is not valid - check to see what went wrong and redirect to the appropriate error page
                            RewriteCond       %{ENV:RETURN_VALUE}                             ^invalid                                                                [NC]
                            RewriteRule       ^(.*)$                                          errors/invalid.html                                                     [L]
                            # ...
                            
                            # If we have a valid download file redirect pass it through
                            RewriteCond       %{ENV:LOAD_FROM_FOLDER}                         !=""
                            RewriteRule       ^(.*)                                           http://download-proxy/%{ENV:LOAD_FROM_FOLDER}/%{REQUEST_URI}            [P,L]
                            Die RewriteMap muss in dem Fall entweder einen Status für ungültig (hier: invalid) zurückgeben oder das Wort "valid" gefolgt von einem Trenner und dem Verzeichnis.
                            VokeIT GmbH & Co. KG - VokeIT-oss @ github

                            Kommentar


                            • #15
                              Tante Edit Danke für deine Mühen, ich vermute mal, ich bekomme es noch irgendwann hin und falls es bei uns dann gut läuft, schreibe ich bald ein enstprechendes Tutorial. Versprochen! ^^

                              Aber jetzt hätte ich erst noch eine Frage. Benutzt du die
                              External Rewriting Program
                              MapType: prg, MapSource: Unix filesystem path to valid regular file
                              Option?

                              Das iss jetzt vielleicht in bissi blöd, aber das PERL Beispielprogramm in der mod_rewrite docu ist mir irgendwie undurchsichtig. Was wäre denn ein PHP Pendant dazu? Warum frisst die While Schleife nicht alle Ressourcen? Gibts irgendein Buch / Artikel / Link, der RewriteMap mit Type "prg" für PHP erklärt?

                              Ein wenig verwirrt,
                              der Bergtroll

                              Kommentar

                              Lädt...
                              X