
Seguridad en el despliegue de aplicaciones Laravel mediante permisos de carpetas
En este artículo abordo, desde la perspectiva de infraestructura y hosting, cómo controlar permisos de archivos y carpetas en aplicaciones Laravel para minimizar riesgos de seguridad, evitar fugas de credenciales y mantener operativas las operaciones de escritura que Laravel necesita. Incluyo comandos prácticos, configuraciones de webserver y estrategias de despliegue seguras aplicables en entornos Linux.
Por qué los permisos importan en Laravel
Laravel requiere que ciertos directorios sean escribibles (por ejemplo storage y bootstrap/cache), pero conceder permisos demasiado laxos abre vectores de ataque: ejecución de código en uploads, lectura de .env por usuarios no autorizados o modificación de archivos críticos. Un enfoque correcto equilibra disponibilidad (la app funciona) y confidencialidad/integridad.
Directorios críticos y permisos recomendados
Identifica las rutas que habitualmente necesitan atención en un proyecto Laravel:
- storage/: logs, caches, archivos subidos.
- bootstrap/cache: caches compilados por Laravel.
- public/: punto de entrada público; aquí solo deben estar archivos estáticos y enlaces simbólicos creados por
php artisan storage:link. - .env: contiene credenciales y claves.
Recomendación numérica segura pero práctica:
- Archivos:
640(propietario lectura/escritura, grupo lectura, otros ninguno). - Directorios:
750(propietario lectura/escritura/ejecución, grupo lectura/ejecución, otros ninguno). .env:600o640, ownership al usuario que ejecuta PHP-FPM o al usuario de despliegue según la estrategia.
Ejemplo de comandos para establecer owner y permisos en un despliegue típico donde el usuario del webserver es www-data:
chown -R www-data:www-data /var/www/miappfind /var/www/miapp -type f -exec chmod 640 {} \;find /var/www/miapp -type d -exec chmod 750 {} \;chmod 600 /var/www/miapp/.env
Si tu usuario de despliegue es distinto (por ejemplo deploy), considera ACLs en lugar de cambiar ownership constantemente.
Uso de ACLs para entornos con usuarios múltiples
Cuando el despliegue es realizado por un usuario diferente al del proceso web, las ACLs permiten dar acceso granular sin comprometer seguridad. Ejemplo práctico:
setfacl -R -m u:www-data:rwX -m u:deploy:rwX /var/www/miapp/storage /var/www/miapp/bootstrap/cachesetfacl -R -d -m u:www-data:rwX -m u:deploy:rwX /var/www/miapp/storage /var/www/miapp/bootstrap/cache
El primer comando asigna permisos en el presente, el segundo configura permisos por defecto para nuevos ficheros y directorios. Para más detalles sobre ACLs consultar la guía de PHP y manejo de ficheros si se trabajan permisos desde código.
Evitar ejecución de código en directorios de subida
Una configuración básica y efectiva es impedir que el servidor web ejecute archivos PHP desde directorios destinados a almacenamiento público o uploads. Para NGINX, puedes usar una ubicación que niegue peticiones a archivos PHP en uploads:
location ~ ^/storage/ { location ~ \.php$ { return 403; } try_files $uri $uri/ =404;}
Ver la documentación de NGINX para adaptar sintaxis: NGINX. En Apache, protege con un .htaccess dentro del directorio de uploads:
<FilesMatch "\.(php|php5|phtml)$"> Require all denied</FilesMatch>
Adicionalmente, valida y normaliza archivos subidos: tamaño, tipo MIME y extensión; usa comprobaciones server-side y escanea con soluciones antivirus en infraestructuras que lo requieran.
Consideraciones sobre .env y secretos
El fichero .env debe ser inaccesible desde la web y con permisos restrictivos. Idealmente, no deberías almacenar secretos en repositorio: usa gestores de secretos (Vault, AWS Parameter Store, etc.) o variables de entorno gestionadas por el sistema de orquestación. Evita exponer .env en backups públicos o en snapshots mal configurados.
Despliegue automatizado y permisos
En pipelines CI/CD hay decisiones críticas que afectan permisos:
- No ejecutes Composer como root en producción. Usa un usuario limitado o contenedores dedicados.
- Realiza operaciones de atomic deploy con releases y symlink (ej. estrategia de Capistrano): sube el release, ejecuta
composer install --no-dev --optimize-autoloader, ejecuta migraciones y luego actualiza el symlink. Ajusta permisos antes de apuntar el symlink. - Usa
umaskadecuado en scripts de despliegue para evitar crear archivos con permisos abiertos. Por ejemploumask 027.
Ejemplo de pasos en un stage de deploy:
# en servidorcd /var/www/miapp/releases/20250601composer install --no-dev --optimize-autoloader --no-interactionphp artisan migrate --forcechown -R www-data:www-data storage bootstrap/cachefind . -type f -exec chmod 640 {} \;find . -type d -exec chmod 750 {} \;ln -sfn /var/www/miapp/releases/20250601 /var/www/miapp/current
SELinux y controles adicionales
Si usas SELinux en sistemas RHEL/CentOS, recuerda que además de permisos posix necesitas ajustar contextos para permitir escritura por parte del servidor. Un ejemplo sería usar chcon para asignar el tipo correcto. Las distribuciones con SELinux requieren validación posterior del comportamiento del servicio web y de PHP-FPM.
Monitorización y auditoría de permisos
Automatiza la detección de permisos peligrosos y ficheros world-writable. Comandos útiles para comprobación:
find /var/www/miapp -type d -perm -0002find /var/www/miapp -type f -perm -o+w
Incluye estas comprobaciones en tu sistema de monitorización o en hooks de CI para bloquear despliegues si aparecen condiciones inseguras. Registra cambios en ownership y permisos con auditd para auditoría forense.
Buenas prácticas adicionales
- Bloquea el acceso a directorios sensibles desde el servidor web, por ejemplo configurando reglas que impidan servir
storage/.gito.env. - Evita dar permisos 777: es la principal causa de incidencias y escalado de riesgo.
- Aplica el principio de menor privilegio: sólo el proceso que necesita escribir debe tener permisos de escritura.
- Revisa dependencias y evita ejecutar binarios de terceros con permisos elevados.
- Revisa las recomendaciones de OWASP sobre gestión de ficheros y carga segura: OWASP.
Checklist práctico antes de pasar a producción
- Ownership correcto: chown al usuario del webserver o aplicar ACLs si hay usuario de despliegue.
- Permisos: archivos 640, directorios 750, .env 600/640.
- Prohibir ejecución de PHP en uploads y storage.
- Automatizar checks en CI: búsqueda de world-writable y pruebas funcionales tras cambiar permisos.
- Configurar backup seguro y políticas de rotación de logs.
Conclusión
Controlar permisos de carpetas en Laravel no es sólo una cuestión de hacer que la aplicación funcione: es una línea de defensa fundamental contra filtraciones de credenciales, ejecución no autorizada de código y modificaciones maliciosas. Aplica una combinación de permisos posix, ACLs cuando haga falta, políticas de despliegue atómicas y reglas de servidor web para bloquear ejecución en uploads. Integra comprobaciones automáticas en tu pipeline CI/CD y documenta la estrategia para que operaciones y desarrollo actúen con coherencia. Para consultas técnicas puntuales, la documentación de PHP, NGINX y los recursos de OWASP son referencias útiles.