Matthias Apsel: sinnvolle Rechtevergabe

Hallo alle,

es passt eigentlich auch irgendwo in diesen Thread hinein …

Ich habe ein PHP-Programm, welches via Browser (u. a. Excel-)Dateien erzeugt, diese in einem Verzeichnis auf dem Server speichert. Außerdem soll PHP den Verzeichnisinhalt lesen können und die Dateien im Browser per Link zum Download anbieten. Die Dateien müssen auch via PHP gelöscht werden können, zum lesen geöffnet werden brauchen sie nicht.

  1. Wie müssen die Rechte für den Ordner gesetzt werden?
  2. Welche Rechte müssen für die Dateien gesetzt werden?
  3. Wie kann ich die Dateirechte beim Erzeugen der Dateien angeben?

Bis demnächst
Matthias

--
Du kannst das Projekt SELFHTML unterstützen,
indem du bei Amazon-Einkäufen Amazon smile (Was ist das?) nutzt.

akzeptierte Antworten

  1. Lieber Matthias,

    mit PHP geschriebene Dateien gehören dem User, unter dem der Webserver den PHP-Prozess ausführt. Wenn PHP die Datei sowohl lesen als auch schreiben können soll, sonst aber niemand, dann benötigt sie diese UNIX-Dateirechte:

    rw- --- --- (600)
    

    Mit den Verzeichnissen ist es im Grunde ebenso, nur dass noch das "ausführen"-Bit notwendig ist, wenn Du Unterverzeichnisse anlegen möchtest.

    rwx --- --- (700)
    

    Solltest Du jetzt mit FTP an diesen Verzeichnissen oder Dateien etwas ändern wollen, dann geht das nur, wenn der FTP-User mit dem User des Webservers identisch ist. Und das ist natürlich Unsinn und wird von daher scheitern. In einem solchen Falle würdest Du diese Dinge über eine gemeinsame Gruppe lösen, in der sich sowohl der FTP-User, als auch der Webserver-Prozess (www-data oder www-run) befinden. Die Rechte sähen dann so aus:

    --- rw- --- (060)
    --- rwx --- (070)
    

    zum lesen geöffnet werden brauchen sie nicht.

    Wenn PHP die Dateien ausliefern soll (also der Link nicht an PHP vorbei vom Webserver über das Dateisystem ausgeliefert wird), dann müssen sie gelesen werden können.

    Wie kann ich die Dateirechte beim Erzeugen der Dateien angeben?

    chmod($dir_path_existing, 0070); // --- rwx ---
    mkdir($dir_path_new, 0070);
    
    touch($file_path);
    chmod($file_path, 0060); // --- rw- ---
    

    Wenn PHP die Zahlenwerte als Oktalzahlen verstehen soll, musst Du sie vierstellig angeben - daher die jeweils zusätzliche führende null. Siehe auch PHP-Doku zu chmod.

    Liebe Grüße

    Felix Riesterer

    1. @@Felix Riesterer

      Die Rechte sähen dann so aus:

      --- rw- --- (060)
      --- rwx --- (070)
      

      Das ist falsch. Die Rechte für den Eigentümer überschreiben die Gruppenrechte. Das heißt, der Dateieigentümer hat – obwohl er in der Gruppe ist – keine Rechte mehr, die Datei zu lesen oder zu bearbeiten.

      Richtig ist:

      rw- rw- --- (660)
      rwx rwx --- (770)
      

      LLAP 🖖

      --
      „Man kann sich halt nicht sicher sein“, sagt der Mann auf der Straße, „dass in einer Gruppe Flüchtlinge nicht auch Arschlöcher sind.“
      „Stimmt wohl“, sagt das Känguru, „aber immerhin kann man sich sicher sein, dass in einer Gruppe Rassisten nur Arschlöcher sind.“

      —Marc-Uwe Kling
      1. @@Felix Riesterer

        Die Rechte sähen dann so aus:

        --- rw- --- (060)
        --- rwx --- (070)
        

        Das ist falsch. Die Rechte für den Eigentümer überschreiben die Gruppenrechte. Das heißt, der Dateieigentümer hat – obwohl er in der Gruppe ist – keine Rechte mehr, die Datei zu lesen oder zu bearbeiten.

        Richtig ist:

        rw- rw- --- (660)
        rwx rwx --- (770)
        

        Nein!

        So lange unbekannt ist, wer denn alles zur "group" (zweites Tripel) gehört und ob all diese Lese- und Schreibrechte (sowie bei Verzeichnissen das Betreten-recht) haben sollen ist das, so wie die Aufgabe formuliert ist, nicht richtig.

        Richtig ist:

        rw- --- --- (600) (Datei)
        rwx --- --- (700) (Verzeichnis)
        

        und also:

        <?php
        umask(077);
        
        1. Das gezeigte Beispiel ist richtig, braucht aber eine Erläuterung:

          und also:

          <?php
          umask(077);
          

          Für alle, die das mit eingeschränkten Rechten für den Eigentümer (user) nachmachen wollen:

          <?php
          # Der Eigentümer soll künftiges, selbst angelegtes
          # Zeug nicht (ohne Weiteres) beschreiben dürfen:
          umask(0277);
          

          Erklärung:

          Umask erwartet ein Integer. Notiert man das "einfach so" dann denken PHP und umask, das sei dezimal. Aus Gründen der einfachen Handhabung hat sich aber die oktale Notation als einfachster Weg erwiesen. Die führende Null für PHP und umask das Zeichen, dass eine Oktalzahl folgt. Aber zwei (im ersten Beispiel 0077) sind dann nicht nötig.

          1. Umask erwartet ein Integer. Notiert man das "einfach so" dann denken PHP und umask, das sei dezimal. Aus Gründen der einfachen Handhabung hat sich aber die oktale Notation als einfachster Weg erwiesen. Die führende Null für PHP und umask das Zeichen, dass eine Oktalzahl folgt. Aber zwei (im ersten Beispiel 0077) sind dann nicht nötig.

            umask nutzt die führende Null nicht zur Anzeige einer Oktalzahl; stattdessen erwartet umask drei oder vier Integers, das erste Zeichen ist dabei optional und wird für die seltener genutzten Special-Permissions (setuid, setgid und sticky) genutzt.

            1. @@erwin

              Umask erwartet ein Integer. […] Die führende Null für PHP und umask das Zeichen, dass eine Oktalzahl folgt.

              umask nutzt die führende Null nicht zur Anzeige einer Oktalzahl; stattdessen erwartet umask drei oder vier Integers, das erste Zeichen ist dabei optional und wird für die seltener genutzten Special-Permissions (setuid, setgid und sticky) genutzt.

              Die Doku sagt etwas anderes. Insb. der Kommentar von malcolm.murphy.

              LLAP 🖖

              --
              „Man kann sich halt nicht sicher sein“, sagt der Mann auf der Straße, „dass in einer Gruppe Flüchtlinge nicht auch Arschlöcher sind.“
              „Stimmt wohl“, sagt das Känguru, „aber immerhin kann man sich sicher sein, dass in einer Gruppe Rassisten nur Arschlöcher sind.“

              —Marc-Uwe Kling
              1. Hello,

                Umask erwartet ein Integer. […] Die führende Null für PHP und umask das Zeichen, dass eine Oktalzahl folgt.

                umask nutzt die führende Null nicht zur Anzeige einer Oktalzahl; stattdessen erwartet umask drei oder vier Integers, das erste Zeichen ist dabei optional und wird für die seltener genutzten Special-Permissions (setuid, setgid und sticky) genutzt.

                Die Doku sagt etwas anderes. Insb. der Kommentar von malcolm.murphy.

                Es kommt darauf an, in welcher Umgebung (Shell, Quelltext für Parser, Programmcode) man die Werte eingibt.

                Siehe hierzu auch die PHP-Doku zu chmod

                Glück Auf
                Tom vom Berg

                --
                Es gibt nichts Gutes, außer man tut es!
                Das Leben selbst ist der Sinn.
            2. umask nutzt die führende Null nicht zur Anzeige einer Oktalzahl; stattdessen erwartet umask drei oder vier Integers, das erste Zeichen ist dabei optional und wird für die seltener genutzten Special-Permissions (setuid, setgid und sticky) genutzt.

              Um 02:00 Uhr morgens erliegt man wegen des Nachlassens der Aufmerksamkeit oft kleinen Irrtümern.

              Was Du beschreibst gilt durchaus, aber eben für den 40 oder 50 Jahre alten(¹) Linux/Unix-Befehl "umask" in einer Linux/Unix, NexTSTEP, OPENSTEP oder MacOS-Shell.

              Der erwartet entweder eine Symbolfolge (a.k.a. 'String') (r.g. 'u=rwx,g=rw,o=') oder eine stets oktal angegebene, ganze Zahl (640) als Argument für die zu setzenden, zu erteilenden oder zu entziehenden Rechte.

              PHP indes vermutet bei einer Folge von Ziffern ohne führende Symbole (0, 0x, 0b) oder gar Stringbegrenzern (', ") einen Integer und reicht den so an die Funktion umask() weiter. Ein Oktalwert wird in PHP durch die führende Null vor den Ziffern als Oktalwert (und das Fehlen von Stringbegrenzern) deklariert. Du könntest ebensogut heaxdezimal (beginnend mit 0x) oder binär (beginnend mit 0b) notierte Werte übergeben..

              Versuche mal:

              <?php
              echo 0b1000; echo PHP_EOL;
              echo 010; echo PHP_EOL;
              echo 0x8; echo PHP_EOL;
              ?>
              # Ergebnis ist stets:
              # 8
              

              Falls Du es probieren willst helfen Dir die Funktionen decoct(), octdec(), decbin(), bindec() und base_convert() aus dem Handbuch um die Darstellungsformen zu ermitteln und dann im Programm zu notieren.

              Allerdings liefern bzw. erwarten diese eine oktale (dezimale, binäre) Stringdarstellung. Funktionen, die einen Integer als Argument erwarten, werden sich vorraussichtlich beschweren wenn Du denen statt dessen einen von decoct(), decbin() oder base_convert() gelieferten String übergibst.


              1. Damalige, mangels Erfahrung "verbrochene" Entwurfsprinzipien für Programmiersprachen gelten heute vielen als "seltsam". Die Entwicklung und Beliebtheit so mancher einst berühmten Programmiersprache (z.B. Perl) leidet auch darunter.
        2. Jemand, der den Beitrag liest könnte wegen der Negativbewertung verunsichert sein und vermeinen, mein Beitrag wäre inhaltlich falsch.

          Es ist aber richtig, die Rechte wie gezeigt auf den Benutzer zu beschränken, denn die Beschreibung lässt unter anderem folgendes Szenario zu:

          • Es gibt auf dem Webserver über 1000 Benutzer.
          • Diese sind verschiedene Kunden des Betreibers.
          • Diese sind sämtlich in einer Gruppe "webusers".

          Derlei ist sehr häufig der Fall und spätestens unter diesen Umständen wäre es schlicht falsch, der Gruppe Lese- und gar Schreibrechte zu gewähren.

          Daher mein klares, und hoffentlich warnendendes "Nein!".

          1. Hello,

            Nur nebenbei:
            hast Du nochmal an mein Scanner-Problem gedacht?

            Glück Auf
            Tom vom Berg

            --
            Es gibt nichts Gutes, außer man tut es!
            Das Leben selbst ist der Sinn.
    2. Hallo Felix Riesterer,

      chmod($dir_path_existing, 0070); // --- rwx ---
      mkdir($dir_path_new, 0070);
      
      touch($file_path);
      chmod($file_path, 0060); // --- rw- ---
      

      Welche Werte sind denn da per default gesetzt?

      Bis demnächst
      Matthias

      --
      Du kannst das Projekt SELFHTML unterstützen,
      indem du bei Amazon-Einkäufen Amazon smile (Was ist das?) nutzt.
      1. Lieber Matthias,

        Welche Werte sind denn da per default gesetzt?

        dafür ist umask da. Aber vielleicht habe ich auch hier nur Halbwissen. Im Zweifelsfalle kannst Du ja eine Datei mittels touch neu erstellen und die Dateirechte daran auslesen.

        Liebe Grüße

        Felix Riesterer

        1. Hallo Felix Riesterer,

          Im Zweifelsfalle kannst Du ja eine Datei mittels touch neu erstellen und die Dateirechte daran auslesen.

          Gute Idee. Stimmt das, was Gunnar da schrieb?

          Bis demnächst
          Matthias

          --
          Du kannst das Projekt SELFHTML unterstützen,
          indem du bei Amazon-Einkäufen Amazon smile (Was ist das?) nutzt.
          1. Hallo Matthias,

            Stimmt das, was Gunnar da schrieb?

            ja. "Gruppe" muss man hier lesen als: Alle Gruppenmitgleider außer dem Besitzer selbst. Das gilt analog für den Rest der Welt, von dem Gruppenmitglieder und der Besitzer ebenfalls ausgenommen sind.

            Will heißen: Du kannst tatsächlich anderen höhere Rechte an einer Datei einräumen, die dir gehört, als dir selbst. Ob und in welchem Fall das sinnvoll ist, kann ich nicht sagen. Mir ist noch kein solcher Fall begegnet, aber das muss ja nichts heißen.

            Ciao,
             Martin

            --
            Frage an die Kollegin am Montagmorgen: "Na, wie war dein Wochenende?"
            Depressive Kollegin: "Hell, dunkel, hell, dunkel, Montag."
          2. @@Matthias Apsel

            Stimmt das, was Gunnar da schrieb?

            Hab ich je was geschrieben, was nicht stimmt? 😝

            Das ist doch schnell ausprobiert. (Hab ich auch vorher gemacht.)

            ~$ echo hallo >> test
            
            ~$ ls -l test
            -rw-r--r--  1 gunnar  staff  6 23 Nov 17:42 test
            
            ~$ cat test
            hallo
            
            ~$ chmod 040 test
            
            ~$ ls -l test
            ----r-----  1 gunnar  staff  6 23 Nov 17:42 test
            
            ~$ cat test
            cat: test: Permission denied
            
            ~$ rm test
            override ---r-----  gunnar/staff for test? y
            
            ~$ ls -l test
            ls: test: No such file or directory
            
            ~$
            

            LLAP 🖖

            --
            „Man kann sich halt nicht sicher sein“, sagt der Mann auf der Straße, „dass in einer Gruppe Flüchtlinge nicht auch Arschlöcher sind.“
            „Stimmt wohl“, sagt das Känguru, „aber immerhin kann man sich sicher sein, dass in einer Gruppe Rassisten nur Arschlöcher sind.“

            —Marc-Uwe Kling
            1. Hallo Gunnar,

              Hab ich je was geschrieben, was nicht stimmt? 😝

              kein Kommentar.

              Eine Sache bei deinen Tests überrascht mich aber:

              ~$ ls -l test
              ----r-----  1 gunnar  staff  6 23 Nov 17:42 test
              
              ~$ cat test
              cat: test: Permission denied
              
              ~$ rm test
              override ---r-----  gunnar/staff for test? y
              
              ~$ ls -l test
              ls: test: No such file or directory
              

              Ich dachte bisher, um eine Datei löschen zu können, muss man keine Schreibrechte für die Datei selbst haben, sondern nur für das Verzeichnis, in dem sie liegt.

              Ciao,
               Martin

              --
              Frage an die Kollegin am Montagmorgen: "Na, wie war dein Wochenende?"
              Depressive Kollegin: "Hell, dunkel, hell, dunkel, Montag."
              1. @@Der Martin

                kein Kommentar.

                😆

                ~$ rm test
                override ---r-----  gunnar/staff for test? y
                
                ~$ ls -l test
                ls: test: No such file or directory
                

                Ich dachte bisher, um eine Datei löschen zu können, muss man keine Schreibrechte für die Datei selbst haben, sondern nur für das Verzeichnis, in dem sie liegt.

                Muss man ja auch nicht; die Datei wird ja gelöscht, ohne das ich Schreibrechte dafür hätte.

                Es kommt nur vorher eine Abfrage. Möglicherweise unterschieden sich auch verschiedene OS (UNIX, Linux, macOS, …) darin.

                LLAP 🖖

                --
                „Man kann sich halt nicht sicher sein“, sagt der Mann auf der Straße, „dass in einer Gruppe Flüchtlinge nicht auch Arschlöcher sind.“
                „Stimmt wohl“, sagt das Känguru, „aber immerhin kann man sich sicher sein, dass in einer Gruppe Rassisten nur Arschlöcher sind.“

                —Marc-Uwe Kling
                1. Muss man ja auch nicht; die Datei wird ja gelöscht, ohne das ich Schreibrechte dafür hätte.

                  Allerdings erst nach der Warnung.

                  Möglicherweise unterschieden sich auch verschiedene OS (UNIX, Linux, macOS, …) darin.

                  Ja. Vor allem im Text.

                  Ich würde dennoch das Schreibrecht an den Dateien setzen. Grund:

                  Außerdem soll PHP den Verzeichnisinhalt lesen können und die Dateien im Browser per Link zum Download anbieten.

                  Dazu muss der Webserver diese lesen können. Das ist "*Kanzerinnenlieblingsersatzwort für Basta!*"

          3. Also.

            Das für Verzeichnis sollten die Sache wie folgt aussehen:

            0700 oder rwx------

            Für die Dateien sollten die Rechte wie folgt aussehen:

            0600 oder rw-------

            <?php
            error_reporting( E_ALL );
            ini_set( 'display_errors', 1 );
            header ('Content-Type: text/plain; charset=utf-8');
            
            
            umask(0077);
            
            echo 'Lege Verzeichnis und Datei an...' . PHP_EOL;
            mkdir ( 'test.dir' );
            file_put_contents ( 'test.dir/test.file', 'Das hat geklappt' );
            echo 'test.dir           :' 
                 . substr( sprintf( '%o', fileperms( 'test.dir' ) ), -4 ) 
                 . PHP_EOL;
            echo 'test.dir/test.file :' 
                 . substr( sprintf( '%o', fileperms( 'test.dir/test.file' ) ), -4 ) 
                 . PHP_EOL;
            echo 'Inhalt: ' 
                 . PHP_EOL
                 . file_get_contents('test.dir/test.file')
                 . PHP_EOL;
            echo 'Lösche...';
            unlink( 'test.dir/test.file' );
            rmdir( 'test.dir' );
            echo 'Keine Fehlermeldung? Dann hat es geklappt ' . PHP_EOL;
            
      2. Welche Werte sind denn da per default gesetzt?

        Ein grep -R 'umask' /etc 2>/dev/null in einer Konsole, am besten nach einem su oder sudo und am besten auf einer gewisser Anzahl verschiedener Installationen, wird Dir zeigen, dass die Beantwortung dieser Frage auf theoretischem Weg durch etwas anderes als "Versuche mal <?=sprintf ("0%s",decoct(umask())); ?>" ein sehr unübersichtliches Unterfangen wird.

  2. Hello,

    das SGID-Bit bitte nicht vergessen. Das kann bei derartigen Upload- und PHP-Szenarien oft hilfreich sein ;-)

    Glück Auf
    Tom vom Berg

    --
    Es gibt nichts Gutes, außer man tut es!
    Das Leben selbst ist der Sinn.