Cómo proteger los contenedores de PHP
Neema Muganga
4 de agosto de 2022
0 minutos de lecturaSegún Wappalyzer, PHP impulsa más de doce millones de sitios web. ¡Nada mal para un lenguaje de 28 años! A pesar de su antigüedad, PHP se ha adaptado a las prácticas modernas de desarrollo. Con compatibilidad para declaraciones de tipos y excelentes frameworks como Laravel y Symfony, PHP sigue siendo una gran opción para desarrollar aplicaciones web.
PHP funciona bien en entornos de contenedores. Con una imagen oficial disponible en Docker Hub, los desarrolladores saben que pueden acceder a imágenes de contenedores PHP probadas exhaustivamente para usarlas como base.
Aun así, los desarrolladores deben tener cuidado al crear imágenes de contenedores para aplicaciones PHP. Como PHP es tan ubicuo y se usa ampliamente, las aplicaciones PHP son un objetivo grande y atractivo para los atacantes. Además, como trabajamos con contenedores y microservicios, es probable que usemos contenedores PHP junto con aplicaciones de terceros, lo que crea otra vía para las vulnerabilidades.
Con demasiada frecuencia, los desarrolladores asumen que el aislamiento de contenedores significa que estos son seguros por naturaleza. Esta suposición incorrecta lleva a bajar la guardia. Tener presente la seguridad sigue siendo esencial, pero con un poco de cuidado y diligencia, desarrollar y ejecutar aplicaciones PHP seguras en contenedores no es difícil.
Con esto en mente, exploremos de forma práctica algunas prácticas recomendadas para proteger los contenedores de PHP.
Requisitos previos
Para implementar estas prácticas recomendadas y seguir esta demostración, asegúrate de tener las siguientes herramientas:
Docker instalado en tu equipo. Usaremos Docker para ejecutar nuestros contenedores PHP y aprovechar sus funciones integradas para protegerlos.
Una cuenta gratuita de Snyk. Usaremos las herramientas de análisis de seguridad de Snyk para detectar y corregir vulnerabilidades en nuestros contenedores.
Node.js para instalar y ejecutar Snyk CLI, o consulta la documentación para instalar Snyk CLI mediante otros métodos.
Prácticas recomendadas para contenedores que debes tener en cuenta
Los contenedores son una forma práctica de ejecutar aplicaciones PHP. Aunque los entornos de ejecución de contenedores, como Docker, los aíslan entre sí y del sistema operativo anfitrión, ese aislamiento no es perfecto y ya se ha eludido en el pasado.
Sin embargo, puedes tomar varias medidas para proteger mejor tus contenedores PHP, entre ellas:
Establece límites de recursos y usa cuotas
Configurar cuotas de recursos por contenedor limita la cantidad de recursos del sistema que este utiliza. Estos recursos incluyen la memoria, la CPU y el ancho de banda de E/S del disco que consume el contenedor. Los desarrolladores de PHP pueden usar varias opciones del entorno de ejecución de contenedores para limitar el acceso del contenedor a los recursos.
CPU
La opción –-cpus <value> especifica la cantidad de CPU que puede usar el contenedor. Por ejemplo, al establecer --cpus 3.5, permitimos que el contenedor use exactamente tres CPU y media, o núcleos de CPU, de los disponibles.
Si necesitas un control más preciso, consulta las opciones cpu-quota y cpu-period en la documentación de Docker. Ten en cuenta que necesitarás entender los períodos del planificador de Linux para usar estas opciones de manera eficaz.
Este es un ejemplo de cómo ejecutar un contenedor PHP con límites de uso de CPU:
Memoria
La opción -m o –memory= establece la memoria máxima disponible para el contenedor. Podemos usar un entero positivo seguido de b, k, m o g para especificar bytes, kilobytes, megabytes o gigabytes, respectivamente.
Por ejemplo, con el comando siguiente, limitaremos la reserva de memoria del contenedor a 800 MB y estableceremos la RAM en una capacidad máxima de 1.5 gigabytes.
Limitar los recursos disponibles para un contenedor reduce el posible impacto de un ataque, ya que disminuye la probabilidad de que consuma tantos recursos que interfiera con el funcionamiento del sistema operativo anfitrión u otros contenedores. Este enfoque mejora la seguridad de cada contenedor y aumenta la seguridad general del entorno anfitrión.
Los contenedores sin cuotas dejan un sistema vulnerable a ataques de denegación de servicio (DoS). Un ataque DoS puede detener los servicios en ejecución de un sistema y perjudicar la calidad del servicio para los usuarios. Esto demuestra que los contenedores sin cuotas pueden convertirse en un riesgo de seguridad para la empresa si no se administran correctamente.
Si ejecutas contenedores PHP con Kubernetes en lugar de Docker, comprender la configuración de contexto de Kubernetes es fundamental para mantener la seguridad de los contenedores.
Evita ejecutar contenedores como root
Lo mejor es evitar ejecutar nuestros contenedores como usuario root o con una cuenta de usuario que tenga más privilegios de los necesarios. En su lugar, siempre debemos seguir el principio de privilegio mínimo al crear cuentas de usuario para nuestros contenedores.
La mayoría de los entornos de ejecución de contenedores ofrecen formas de ejecutarlos con una cuenta de usuario que no sea root. Docker ofrece un modo sin privilegios de root para ejecutar el entorno de ejecución y todos sus contenedores con una cuenta de usuario normal.
Kubernetes también ofrece varias opciones para ejecutar nodos y contenedores sin privilegios de root. En general, cualquier entorno de ejecución de contenedores compatible con OCI permite especificar exactamente qué usuario y grupo debe usar mediante las propiedades UID y GID en nuestro archivo de configuración del entorno de ejecución.
De hecho, quienes usan Snyk para analizar sus archivos de configuración de Kubernetes o sus archivos de IaC de Terraform se beneficiarán de la detección de las configuraciones incorrectas mencionadas, como No se establecieron límites de memoria o El contenedor se ejecuta como root. Snyk las destaca visualmente e incluye una referencia a las líneas de código del archivo YAML que no siguen estas prácticas recomendadas de seguridad:

Tomemos Docker como ejemplo. Ejecutar nuestros contenedores PHP en modo sin privilegios de root no es muy distinto a cuando Docker se ejecuta como root. Todos los comandos habituales de Docker deberían funcionar, pero recuerda que los privilegios que podemos otorgar a un contenedor estarán limitados por los de la cuenta de usuario con la que ejecutemos el daemon de Docker. Hay una salvedad: si ya instalaste el daemon de Docker con su configuración predeterminada, tendrás que desinstalarlo y volver a instalarlo en modo sin privilegios de root, siguiendo las instrucciones de la documentación de Docker.
Evita usar un usuario root dentro de los contenedores
Además de ejecutar los contenedores en modo sin privilegios de root, deberíamos evitar usar un usuario root dentro del contenedor. Aunque esto pueda parecer redundante si ya lo ejecutamos en modo sin privilegios de root, proporciona una capa adicional de defensa contra usuarios maliciosos.
Podemos ejecutar nuestro contenedor PHP como un usuario que no sea root con la directiva USER en el Dockerfile, para que el contenedor se ejecute en el contexto de un usuario o grupo con la menor cantidad posible de privilegios.
Si una imagen base de Docker no incluye un usuario con pocos privilegios, podemos agregar un usuario que no sea root durante el proceso de creación de la imagen. Así estará disponible al crear una nueva imagen de contenedor, como se muestra en el siguiente Dockerfile:
Las imágenes oficiales de contenedores PHP incluyen una cuenta de usuario sin privilegios llamada nobody. Por eso, si estás creando una imagen de contenedor basada en una de las imágenes base oficiales de Docker, puedes usar este usuario en lugar de crear uno manualmente, como se mostró antes:
Ahora, si ejecutamos la imagen de Docker en modo interactivo e intentamos ver el archivo de texto creado para el usuario root en el Dockerfile, veremos que no tenemos permiso:
La conclusión principal es que evitar usar root tanto en el entorno de ejecución como dentro de los contenedores significa que una imagen de aplicación Docker maliciosa, o una aplicación comprometida en un contenedor, tendría que llevar a cabo dos ataques exitosos de escalamiento de privilegios para vulnerar el sistema operativo anfitrión donde se ejecuta el contenedor y, desde ahí, continuar con el movimiento lateral.
Sin embargo, no siempre es posible usar contenedores sin privilegios de root. A veces, las aplicaciones en contenedores necesitan acceder a hardware, como la GPU. Por suerte, podemos agregar otras capas de defensa.
Corrige las vulnerabilidades de los contenedores con herramientas automatizadas
Los contenedores pueden esconder muchas vulnerabilidades. Las bibliotecas y aplicaciones incluidas en la imagen base, así como los paquetes adicionales que instales, pueden contener CVE u otras vulnerabilidades. Si fuera así, ¿cómo te enterarías? La mayoría de los equipos de desarrollo y DevOps no tienen tiempo para hacer un seguimiento manual del historial de seguridad de cada paquete instalado en sus contenedores.
Por suerte, el análisis automatizado de contenedores puede ayudar. Snyk Container es gratis y puede analizar automáticamente nuestras imágenes y notificarnos de inmediato sobre las vulnerabilidades en los paquetes y las bibliotecas de código abierto dentro de nuestros contenedores. Así podemos implementar correcciones en cuanto aparece una vulnerabilidad, antes de que los atacantes puedan aprovecharla. Snyk también propondrá correcciones automáticamente mediante la apertura de pull request con una imagen base actualizada y etiquetas de imagen recomendadas.
Snyk permite analizar nuestros contenedores en busca de vulnerabilidades de forma rápida y sencilla. Si tenemos Node.js y npm instalados, solo debemos ejecutar npm install snyk@latest -g para instalar Snyk CLI.
Luego, ejecuta:
Este comando abrirá una página de autenticación en el navegador:

"blog-php-container-authenticateAl hacer clic en el botón Authenticate, aparecerá un mensaje de autenticación exitosa en la terminal.
Ahora podemos usar Snyk CLI para analizar nuestros contenedores. Para ello, ejecutamos:
Al ejecutarlo en una imagen base de PHP 7.4, obtenemos lo siguiente:

Lo ideal es ejecutar un análisis de contenedores en nuestro pipeline de CI/CD para asegurarnos de no implementar nunca un contenedor vulnerable en producción. También podemos usar el comando de monitoreo de contenedores para enviar a Snyk los datos de prueba de la imagen. Así, Snyk puede mostrar la información en nuestro panel y notificarnos sobre posibles vulnerabilidades futuras en la imagen.
Al ejecutarlo en la misma imagen de PHP que acabamos de probar, obtenemos lo siguiente:

¿Así de fácil? Y aún no terminamos. También podemos usar Snyk Code para asegurarnos de que nuestro código PHP sea seguro antes de crear un contenedor.
Ve a la carpeta donde se encuentra el archivo de manifiesto de tu aplicación PHP y ejecuta el siguiente comando para ver el resultado:
Podemos ejecutar una prueba de Snyk Code en un proyecto antiguo de Laravel para probar un caso común: encontrar vulnerabilidades en un proyecto PHP desactualizado que todavía funciona. Este es el resultado:

Al igual que con el monitoreo de contenedores, también podemos permitir que Snyk monitoree nuestra base de código. Para ello, ejecutamos snyk monitor en el directorio principal de nuestra aplicación PHP. Luego, veremos la aplicación en nuestro panel de Snyk.

El análisis de seguridad a nivel de contenedor y de código es una excelente manera de asegurarnos de entregar contenedores y código seguros.
Usa imágenes de contenedores confiables
Una forma de proteger nuestros contenedores PHP es descargar imágenes de registros en línea seguros y confiables. Es menos probable que estos registros confiables contengan imágenes con código malicioso o desactualizado que pueda exponer nuestro entorno de contenedores a una filtración de datos. Por ejemplo, Docker Hub incluye diversas imágenes confiables que Docker revisa minuciosamente en busca de vulnerabilidades y cuyos proveedores también verifica, para que los usuarios puedan acceder a ellas.
Sin embargo, no todas las imágenes de Docker Hub son confiables. Al usar registros en línea, debemos revisar el contenido de las imágenes para detectar posibles vulnerabilidades de seguridad. Podemos analizar la imagen en busca de código malicioso que represente una amenaza para el contenedor antes de descargarla en el sistema anfitrión. Para asegurarnos de no omitir este paso, podemos integrar directamente una herramienta de seguridad como Snyk en nuestras herramientas o flujos de trabajo de desarrollo, a fin de monitorear y corregir posibles vulnerabilidades de seguridad en nuestros contenedores.
Además de escanear, podemos asegurarnos de usar imágenes de contenedor confiables mediante Docker Hub, el programa Docker Verified Publisher y Docker Official Images. El programa Docker Verified Publisher valida que las imágenes obtenidas allí provengan de fuentes confiables, para que los usuarios no descarguen imágenes inseguras de repositorios falsos.
Otra opción es usar imágenes verificadas por Docker Content Trust. Docker 1.8 introdujo Docker Content Trust para reforzar la firma digital y la autenticación de imágenes. La firma de imágenes valida el origen de una imagen de contenedor y verifica que no se haya alterado. También establece las políticas que determinan qué imágenes validadas pueden descargar los usuarios en sus sistemas.
Aunque descargues las imágenes oficiales de Docker de publicadores verificados por Docker o uses Docker Content Trust para proteger tu entorno de contenedores, es fundamental usar Snyk para proteger tus contenedores.
Los desarrolladores de PHP son responsables de la seguridad de sus contenedores
Para proteger los contenedores PHP de posibles amenazas de seguridad, es necesario implementar varias técnicas de seguridad a lo largo del ciclo de vida de la aplicación, desde la compilación hasta la implementación y la ejecución. Además de seguir las prácticas recomendadas de seguridad de contenedores para aplicaciones PHP, podemos recurrir a Snyk para mantener la seguridad de los contenedores mediante herramientas automatizadas, como:
Pruebas de seguridad automatizadas en pipelines de CI/CD, como las integraciones con GitHub Actions o AWS Code Pipeline
Inteligencia de seguridad unificada para contenedores y código fuente
Integración con Kubernetes para monitorear y observar los contenedores en nuestros clústeres de Kubernetes y detectar vulnerabilidades nuevas o existentes
Un enfoque centrado en los desarrolladores que detecta problemas de seguridad en tu propio código PHP y facilita su corrección, incluso si no tienes experiencia amplia en seguridad
Snyk Container es una herramienta de gestión de vulnerabilidades en contenedores que nos ayuda a identificar y resolver sus problemas de seguridad de forma exhaustiva y eficiente. Gracias a las comprobaciones integradas en el IDE, la integración automatizada con CI/CD, el escaneo nativo de Git y las pruebas en el entorno de producción, Snyk Container protege nuestros contenedores y cargas de trabajo de Kubernetes durante todo el ciclo de vida del desarrollo de software.
Seguridad de contenedores centrada en los desarrolladores
Snyk encuentra y corrige automáticamente vulnerabilidades en imágenes de contenedores y cargas de trabajo de Kubernetes.
Además, Snyk puede ayudar a identificar vulnerabilidades al integrar el escaneo de seguridad en herramientas de desarrollo como VS-Code y JetBrains mientras desarrollas aplicaciones, para ofrecerte más información sobre los tipos de vulnerabilidades y las correcciones sugeridas.
Snyk también ayuda a los desarrolladores a identificar vulnerabilidades que ponen en riesgo la seguridad de los contenedores. Las corrige automáticamente, lo que aumenta la productividad y permite que los equipos de desarrollo dediquen menos tiempo a corregir código y más tiempo a crear aplicaciones. Crea tu cuenta gratis hoy mismo. También puedes probar nuestra herramienta gratuita en línea para revisar código PHP y ver cómo el motor de Snyk Code analiza tu código en busca de problemas de seguridad y calidad.



