sinnvolle Rechtevergabe
Matthias Apsel
- dateisystem
- php
- sicherheit
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.
Bis demnächst
Matthias
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
@@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 🖖
@@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);
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.
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.
@@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 🖖
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
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.
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:
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.
Hello,
Nur nebenbei:
hast Du nochmal an mein Scanner-Problem gedacht?
Glück Auf
Tom vom Berg
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
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
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
@@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 🖖
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
@@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 🖖
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!*"
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;
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.
Hello,
das SGID-Bit bitte nicht vergessen. Das kann bei derartigen Upload- und PHP-Szenarien oft hilfreich sein ;-)
Glück Auf
Tom vom Berg