W3docs

chroot()

Erfahren Sie, wie PHP's chroot() das Root-Verzeichnis eines Prozesses ändert, um eine isolierte Dateisystem-Umgebung zu schaffen – mit Syntax und Beispielen.

PHP chroot() Funktion

Die Funktion chroot() ändert das Root-Verzeichnis des aktuell laufenden Prozesses auf das angegebene Verzeichnis und setzt das aktuelle Arbeitsverzeichnis anschließend auf /. Nach dem Aufruf kann der Prozess keine Datei mehr sehen oder erreichen, die sich oberhalb dieses neuen Root befindet — er ist innerhalb des Verzeichnisbaums "eingesperrt". Diese Technik wird allgemein als chroot-Jail bezeichnet.

Diese Seite erklärt, was chroot() tut, wann man es verwenden sollte (und wann nicht), seine Syntax sowie die Einschränkungen, die man kennen muss, bevor man sich darauf verlässt.

Syntax

chroot(string $directory): bool
ParameterBeschreibung
$directoryDer Pfad zu dem Verzeichnis, das zum neuen Root (/) des Prozesses wird.

Rückgabewert: true bei Erfolg, false bei Fehler.

Voraussetzungen

chroot() ist nicht überall verfügbar. Beachten Sie vor der Verwendung folgende Einschränkungen:

  • Es funktioniert nur unter CLI- und CGI-SAPIs — es ist nicht unter den meisten Modul-SAPIs wie mod_php oder PHP-FPM verfügbar, wenn diese eine typische Web-Anfrage verarbeiten.
  • Es ist nicht unter Windows implementiert.
  • Der aufrufende Prozess muss über Root-Rechte (Superuser-Rechte) verfügen. Ein normaler Benutzer kann das Root-Verzeichnis nicht ändern.

Aufgrund dieser Voraussetzungen wird chroot() hauptsächlich in langlebigen PHP-CLI-Daemons und Worker-Skripten verwendet, nicht in Code, der gewöhnliche HTTP-Anfragen verarbeitet.

Einfaches Beispiel

Dieses Skript sperrt den Prozess in /var/www/jail ein und liest anschließend einen Pfad relativ zum neuen Root:

<?php
// Must be run as root, on CLI.
if (chroot('/var/www/jail')) {
    echo "Root directory changed.\n";

    // Paths are now relative to /var/www/jail.
    // What was /var/www/jail/data/config.txt is now /data/config.txt
    $contents = file_get_contents('/data/config.txt');
    echo $contents;
} else {
    echo "Failed to change root directory.\n";
}

Nach dem Aufruf von chroot() verweist der Pfad /data/config.txt tatsächlich auf /var/www/jail/data/config.txt im echten Dateisystem. Der Prozess kann schlicht keinen Pfad ausdrücken, der aus dem Jail ausbricht.

Das Arbeitsverzeichnis bestätigen

Da chroot() das Arbeitsverzeichnis ebenfalls auf / setzt, können Sie die Änderung mit getcwd() bestätigen:

<?php
chroot('/var/www/jail');

echo getcwd();   // "/"  (which is /var/www/jail on the real filesystem)

Falls Sie ein anderes Arbeitsverzeichnis innerhalb des Jails benötigen, setzen Sie es nach dem chroot()-Aufruf explizit mit chdir().

Warum chroot() verwenden

Das Ziel von chroot() ist Isolation. Sobald ein Prozess eingesperrt ist:

  • Kann er keine Dateien außerhalb des neuen Root öffnen, lesen oder schreiben, selbst nicht mit absoluten Pfaden.
  • Hat ein Fehler oder Exploit, der Directory-Traversal (../../etc/passwd) versucht, nichts, das er durchqueren kann — es gibt keinen Pfad oberhalb von /.
  • Können Sie einen minimalen Verzeichnisbaum bereitstellen (nur die Dateien, die der Worker tatsächlich benötigt), was die Angriffsfläche verringert.

Ein gängiges Muster besteht darin, einen Daemon als Root zu starten, chroot() aufzurufen, um ihn in eine Sandbox einzusperren, und dann mit posix_setuid() / posix_setgid() Privilegien abzugeben, sodass der eingesperrte Prozess nicht mehr als Root läuft.

chroot() vs. open_basedir

Diese werden häufig verwechselt. Sie lösen ein ähnliches Problem auf sehr unterschiedlichen Ebenen:

chroot()open_basedir
EbeneRoot des Betriebssystem-ProzessesPfadprüfung der PHP-Engine
Wo gesetztIm Code zur Laufzeitphp.ini, .htaccess, FPM-Pool
Funktioniert unter Web-SAPIsNein (nur CLI/CGI)Ja
Root-Rechte erforderlichJaNein
StärkeVom Betriebssystem erzwungenes JailEmpfehlend, kann durch Symlinks geschwächt werden

Wenn Sie nur eine normale Web-Anfrage in einem Verzeichnis halten möchten, ist open_basedir das praktische Werkzeug. Verwenden Sie chroot(), wenn Sie einen CLI-Prozess kontrollieren und eine echte Grenze auf Betriebssystemebene wünschen.

Einschränkungen und Fallstricke

  • Keine perfekte Sicherheitsgrenze. Ein Prozess, der im Chroot noch als Root läuft, kann häufig ausbrechen. Geben Sie Privilegien immer nach dem Einsperren ab.
  • Fehlende Abhängigkeiten. Das Jail besitzt kein /lib, /etc, /usr, es sei denn, Sie legen sie dort ab. Funktionen, die auf Systemdateien angewiesen sind (DNS-Abfragen, Locale-Daten, Zeitzonen, dynamische Bibliotheken), können innerhalb des Jails fehlschlagen.
  • Einmalig für den Prozess. Es gibt kein unchroot(); die Änderung gilt für die gesamte Lebensdauer des Prozesses.
  • Umgebungsabhängig. Da die Verfügbarkeit von SAPI und Betriebssystem abhängt, sollten Aufrufe abgesichert und der Rückgabewert überprüft werden, anstatt Erfolg vorauszusetzen.

Fazit

chroot() begrenzt einen PHP-Prozess auf einen einzelnen Verzeichnisbaum, indem es dessen Root auf dieses Verzeichnis ändert und das Arbeitsverzeichnis auf / zurücksetzt. Es ist ein leistungsstarkes Isolationswerkzeug auf Betriebssystemebene für privilegierte CLI-Daemons, erfordert jedoch Root-Rechte, ist auf CLI/CGI beschränkt und unter Windows nicht verfügbar. Für Einschränkungen pro Anfrage in einem normalen Web-Stack greifen Sie stattdessen auf open_basedir zurück und betrachten chroot() als eine Schicht einer Defense-in-Depth-Strategie. Weitere Informationen zur Arbeit mit Pfaden und dem Dateisystem finden Sie unter chdir(), getcwd() und im Kapitel PHP Filesystem.

Diagramm

So verändert chroot(), was ein Prozess erreichen kann:

graph TD;
    A[PHP Process] --> B{chroot('/var/www/jail')};
    B --> C[New root = /var/www/jail];
    C --> D[Working dir set to /];
    D -->|Path /data/config.txt| E[Allowed: inside jail];
    D -->|Path ../../etc/passwd| F[Blocked: nothing above /];

Hinweis: Die Grenze wird vom Betriebssystem durchgesetzt und gilt daher für jeden Datei-Vorgang des Prozesses, nicht nur für PHP-Funktionsaufrufe.

Übungen

Übung
Was ist der Zweck der chroot-Funktion in PHP?
Was ist der Zweck der chroot-Funktion in PHP?
Was this page helpful?