W3docs

chroot()

Aprende cómo la función chroot() de PHP cambia el directorio raíz de un proceso para crear un entorno de sistema de archivos aislado, con sintaxis y ejemplos.

Función PHP chroot()

La función chroot() cambia el directorio raíz del proceso en ejecución al directorio que se le indica y luego establece el directorio de trabajo actual en /. Tras la llamada, el proceso no puede ver ni acceder a ningún archivo por encima de esa nueva raíz — queda "enjaulado" dentro del árbol de directorios. Esta técnica se conoce comúnmente como chroot jail.

Esta página explica qué hace chroot(), cuándo usarla (y cuándo no), su sintaxis y las limitaciones que debes conocer antes de depender de ella.

Sintaxis

chroot(string $directory): bool
ParámetroDescripción
$directoryLa ruta al directorio que se convierte en la nueva raíz (/) del proceso.

Valor de retorno: true si tiene éxito, false si falla.

Requisitos

chroot() no está disponible en todos los entornos. Antes de usarla, ten en cuenta estas restricciones:

  • Funciona solo con SAPIs de CLI y CGIno está disponible en la mayoría de los SAPIs de módulo, como mod_php o PHP-FPM ejecutando una solicitud web típica.
  • No está implementada en Windows.
  • El proceso que realiza la llamada debe tener privilegios de superusuario (root). Un usuario normal no puede cambiar el directorio raíz.

Debido a estos requisitos, chroot() se usa principalmente en demonios CLI de larga ejecución y scripts de trabajo, no en código que gestiona solicitudes HTTP ordinarias.

Ejemplo básico

Este script enjaulan el proceso dentro de /var/www/jail y luego lee una ruta relativa a la nueva raíz:

<?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";
}

Después de la llamada a chroot(), la ruta /data/config.txt hace referencia en realidad a /var/www/jail/data/config.txt en el sistema de archivos real. El proceso simplemente no puede expresar una ruta que escape de la jaula.

Confirmar el directorio de trabajo

Dado que chroot() también mueve el directorio de trabajo a /, puedes confirmar el cambio con getcwd():

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

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

Si necesitas un directorio de trabajo diferente dentro de la jaula, establécelo explícitamente con chdir() después de la llamada a chroot().

Por qué usar chroot()

El objetivo de chroot() es el aislamiento. Una vez que un proceso está enjaulado:

  • No puede abrir, leer ni escribir archivos fuera de la nueva raíz, ni siquiera con rutas absolutas.
  • Un error o exploit que intente un recorrido de directorio (../../etc/passwd) no tiene nada hacia donde recorrer — no existe ninguna ruta por encima de /.
  • Puedes incluir un árbol de directorios mínimo (solo los archivos que el trabajador necesita realmente), reduciendo la superficie de ataque.

Un patrón común es iniciar un demonio como root, llamar a chroot() para encerrarlo en un entorno aislado y luego eliminar los privilegios con posix_setuid() / posix_setgid() para que el proceso enjaulado ya no se ejecute como root.

chroot() vs open_basedir

Estos dos mecanismos se confunden con frecuencia. Resuelven un problema similar en niveles muy diferentes:

chroot()open_basedir
NivelRaíz del proceso a nivel de sistema operativoVerificación de ruta del motor PHP
Dónde se configuraEn el código en tiempo de ejecuciónphp.ini, .htaccess, grupo FPM
Funciona con SAPIs webNo (solo CLI/CGI)
Requiere privilegios rootNo
SolidezJaula impuesta por el SOOrientativa, puede debilitarse con enlaces simbólicos

Si solo necesitas mantener una solicitud web normal dentro de un directorio, open_basedir es la herramienta práctica. Usa chroot() cuando controlas un proceso CLI y quieres un límite real a nivel de sistema operativo.

Limitaciones y advertencias

  • No es un límite de seguridad perfecto. Un proceso que aún se ejecute como root dentro de un chroot puede frecuentemente escapar de él. Siempre elimina los privilegios después de enjaular.
  • Dependencias faltantes. La jaula no tiene /lib, /etc, /usr a menos que los incluyas. Las funciones que dependen de archivos del sistema (consultas DNS, datos de configuración regional, zonas horarias, librerías dinámicas) pueden fallar dentro de la jaula.
  • Unidireccional para el proceso. No existe unchroot(); el cambio dura toda la vida del proceso.
  • Depende del entorno. Dado que la disponibilidad depende del SAPI y del sistema operativo, protege las llamadas y verifica el valor de retorno en lugar de asumir que tendrán éxito.

Conclusión

chroot() confina un proceso PHP a un único árbol de directorios cambiando su raíz a ese directorio y restableciendo el directorio de trabajo a /. Es una potente herramienta de aislamiento a nivel de sistema operativo para demonios CLI con privilegios, pero requiere acceso root, está limitada a CLI/CGI y no está disponible en Windows. Para restricciones por solicitud en una pila web normal, recurre a open_basedir y trata chroot() como una capa más de una estrategia de defensa en profundidad. Para aprender más sobre cómo trabajar con rutas y el sistema de archivos, consulta chdir(), getcwd() y el capítulo PHP Filesystem.

Diagrama

Así es como chroot() transforma lo que un proceso puede alcanzar:

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 /];

Nota: El límite es impuesto por el sistema operativo, por lo que se aplica a cada operación de archivo que realiza el proceso, no solo a las llamadas de funciones PHP.

Práctica

Práctica
¿Cuál es el propósito de la función chroot en PHP?
¿Cuál es el propósito de la función chroot en PHP?
Was this page helpful?