El ticket dice "Permiso denegado" en "almacenamiento/registros". La respuesta rápida: chmod -R 777 almacenamiento. La aplicación vuelve a funcionar. Tres meses después, se ejecuta un .php depositado en storage/uploads porque nginx todavía estaba sirviendo este directorio.
Los permisos web no son burocracia de Unix: separación entre código, datos, cargas y ejecución.
Modelo recomendado
Código (implementación de git): propietario humano/CI, web de solo lectura. Datos (almacenamiento, caché): escritura de datos www dirigida. Subidas: subárbol sin intérprete.
| Camino | Propietario | Moda | Nota |
|---|---|---|---|
| aplicación/ | implementar:www-data | 750/640 | sin carga |
| almacenamiento/ | www-datos | 770 directorios | registros, caché |
| público/cargas | www-datos | 750 | noexec si es posible |
umask y systemd
umask 027 o 002 según modelo de grupo. PHP-FPM user=www-data, grupo separado por aplicación multiinquilino.
Evite ejecutar scripts de implementación como root sin el chown final.
nginx / Apache
location ^~ /uploads/ { location ~ \.php$ { deny all; } } — bloquea la ejecución incluso si se carga el archivo .php.
Separe el usuario de vhost si el alojamiento compartido está restringido.
ACL para casos corruptos
setfacl -m u:www-data:rwX storage sin abrir el mundo. Restablecer ACL después de restaurar la copia de seguridad: a menudo se olvida.
Auditoría automatizada
Script posterior a la implementación: falla si find . -perm -0002. Alertas sobre SUID nuevas. Documente la excepción temporal con ticket y fecha de caducidad.
Auditoría de permisos exprés
buscar /var/www -tipo f -perm -0002
buscar /var/www -tipo d -perm -0002
buscar /var/www -nombre '*.php' -ruta '*/uploads/*'
Correcto: chown implementar:www-data, chmod 640 archivos/750 directorios, nginx niega las cargas de PHP.
Excepciones de documentos con billete y fecha de caducidad. Vuelva a escanear el CI posterior a la implementación.
Entrenamiento de desarrollo: “permiso denegado” → strace/id/groups antes de chmod.
Un único directorio de carga en el que se pueda escribir a nivel mundial es suficiente para comprometer una pequeña cadena de suministro de CMS.
SELinux/AppArmor en distribuciones reforzadas: a veces se requiere chcon después de la implementación: contextos de documentos, no solo chmod.
Contenedores: mapeo de UID de montaje de volumen: permiso denegado, misterioso, a menudo host de UID ≠ usuario del contenedor.
Permisos de deuda técnica
Legado de auditoría: el antiguo proveedor chmod 777 storage no está documentado en ninguna parte. Plan de remediación de Sprint: nginx deny + ACL + chown.
Usuario del grupo PHP-FPM por cliente multiinquilino si se comparte de forma personalizada: aislamiento por usuario de Unix > mundo chmod.
Git no realiza un seguimiento de los permisos de forma predeterminada: modos de restauración de gancho posteriores al pago si es necesario.
Resumen operativo
Los permisos correctos en el alojamiento web separan la lectura, escritura y ejecución por función: implementar escribe código, www-data escribe cargas y caché, nadie ejecuta PHP en las cargas. El sistema compartido a veces compensa con open_basedir; VPS requiere disciplina explícita.
Auditoría de webshell posterior al incidente: chmod por sí solo es insuficiente: nginx deniega la ejecución, secretos de rotación, análisis de carga de vectores. Integre los permisos de escaneo en la implementación de CI. Entrenamiento: permiso denegado → propietario/grupo antes del modo.
Guía paso a paso
- Identifique el usuario PHP-FPM (
ps aux | grep php-fpm). - Enumere la raíz web del propietario actual (
namei -l /var/www/app/public). - Aplique implementar: www-data 750/640 en el código.
- almacenamiento y carga 770/750 www-data.
- nginx niega PHP en las cargas.
- Escanee CI con capacidad de escritura mundial.
- Excepciones de documentos.
En caso de incidente de carga maliciosa: aísle vhost, conserve el archivo para su análisis, rote la contraseña de la base de datos si se sospecha que se inyecta SQL, restaure los permisos de IaC, no del pánico chmod manual.
Mantenga un runbook fechado, métricas de antes y después, revisión posterior al incidente: la disciplina acumulativa evita el pánico del viernes por la noche.
Mantenga un runbook fechado, métricas de antes y después, revisión posterior al incidente: la disciplina acumulativa evita el pánico del viernes por la noche.
Mantenga un runbook fechado, métricas de antes y después, revisión posterior al incidente: la disciplina acumulativa evita el pánico del viernes por la noche.
Mantenga un runbook fechado, métricas de antes y después, revisión posterior al incidente: la disciplina acumulativa evita el pánico del viernes por la noche.
Mantenga un runbook fechado, métricas de antes y después, revisión posterior al incidente: la disciplina acumulativa evita el pánico del viernes por la noche.
Mantenga un runbook fechado, métricas de antes y después, revisión posterior al incidente: la disciplina acumulativa evita el pánico del viernes por la noche.
CMS
WP carga archivos no ejecutivos, almacenamiento Laravel solo grabable. Permisos de implementación de enlaces simbólicos en la actualidad.
Decide y avanza sin puntos ciegos
- Identifique el usuario de PHP-FPM —
namei -len la raíz web, implementación del propietario:www-data. - Aplicar 750/640 al código: almacenamiento y cargas 770/750, nginx niega PHP en las cargas.
- Escanear con capacidad de escritura mundial: busque en CI las excepciones con ticket posteriores a la implementación con fecha de vencimiento.
- Capacite a los desarrolladores — permiso denegado → strace/id/groups antes del pánico de chmod 777.
- Restaurar desde IaC después de un incidente de carga maliciosa: sin chmod manual de emergencia.
Compartido vs VPS: compare los límites a través del directorio y nuestras guías de seguridad.
Preguntas frecuentes
¿chmod 755 o 775 para un sitio web?
755 en archivos estáticos si www-data se lee solo. 775 solo si varios usuarios del grupo deben escribir: grupo estricto, nunca de escritura mundial.
¿Propietario de www-data o implementación?
Archivos de aplicación: implementación: www-data 640, carpetas 750. Cargas: www-data escribible, ejecución de PHP deshabilitada en el directorio de carga a través de nginx.
¿ACL frente a chmod recursivo?
setfacl para casos específicos (implementar + www-data). chmod -R 777 es un antipatrón que oculta el conflicto real entre usuario y grupo.
¿Cómo auditar?
busque escritura mundial, encuentre SUID inesperado, verifique las rutas de carga. Integre en CI o script posterior a la implementación.
Siguiente error: permiso denegado: cambiar propietario antes del modo, en ese orden, siempre.
