Aviso: Este artículo es de marzo de 2007, en aquella época había poca información de este mod y parecía una solución elegante y sencilla. A día de hoy desconozco el estado de este módulo para Apache pero me parece interesante recuperar el artículo del aquel blog desaparecido.
A continuación explicaré cómo enjaular Apache con PHP y MySQL en un entorno chroot usando mod_chroot. Se trata típico entorno LAMP, en este caso sobre Debian Etch, Apache2 con SSL, PHP5 y MySQL5.
Una definición rápida de chroot: es un entorno (jaula) que cambia el directorio raíz, las aplicaciones que se ejecuten dentro del chroot lo harán dentro de este entorno sin poder acceder fuera de ese directorio. Chroot tiene infinidad de aplicaciones, en este caso será por seguridad; si alguien aprovecha un fallo de seguridad en nuestro servidor web no podrá salir de este entorno chroot y tampoco podrá usar herramientas que no se hayan facilitado (o eso dice la teoría).
Para enjualar Apache en un entorno chroot existen distintas alternativas, con sus ventajas e inconvenientes. Que yo conozca:
- Con el clásico comando chroot de toda la vida. Es el más polivalente.
Chroot Apache FreeBSD - mod_security de Apache. Es un mod muy útil en temas de seguridad.
Enjaular Apache con mod_security CHROOT - mod_chroot de Apache. Es un mod que simplifica la tarea de enjaular Apache, aunque de momento poco documentado. Este es el método que se explicará a continuación.
mod_chroot
Apache
Lo primero es instalar Apache2 y mod_chroot
apt-get install apache2 libapache2-mod-chroot
Crear el directorio chroot, por ejemplo
mkdir -p /var/chroot/apache2
y dentro el siguiente árbol de directorios
|-- etc |-- lib |-- tmp |-- usr | |-- lib | `-- share | `-- zoneinfo | `-- Europe `-- var |-- lib |-- run | `-- apache2 `-- www
Es muy importante que el usuario de Apache (www-data por defecto en Debian) tenga permisos de lectura y escritura sobre el directorio /tmp.
Copiar el pid file, el archivo con los tipos MIME, resolv.conf y hosts:
mv /var/run/apache2.pid /var/chroot/apache2/var/run/apache2.pid
cp /etc/mime.types /var/chroot/apache2/etc/
cp /etc/hosts /var/chroot/apache2/etc/
cp /etc/resolv.conf /var/chroot/apache2/etc/
cp /usr/share/zoneinfo/Europe/Madrid /var/chroot/apache2/usr/share/zoneinfo/Europe/
En caso de modificar la ip del equipo o los hosts habrá que actualizar el archivo resolv.conf y hosts respectivamente, de todas formas no son archivos imprescindibles.
Es importante crear un enlace al archivo apache2.pid fuera de la jaula:
ln -s /var/chroot/apache2/var/run/apache2.pid /var/run/apache2.pid
Por último solo falta activar el chroot y configurarlo:
a2enmod mod_chroot
En Debian el archivo de configuración de Apache2 es /etc/apache2/apache2.conf en vez del clásico httpd.conf, de todas formas es incluido en el primero. Añadir las siguientes líneas en /etc/apache2/httpd.conf
PidFile /var/run/apache2.pid
ChrootDir /var/chroot/apache2/
Con esto ya estaría Apache2 dentro de un entorno chroot. Para probarlo crear un archivo html en /var/chroot/apache2/var/www/, reiniciar apache y probar que carga la página
/etc/init.d/apache2 restart
Para tener conexión cifrada con SSL activar el mod (suele venir por defecto) e instalar el paquete openssl
apt-get install openssl
a2enmod ssl
Hay que crear un certificado, como somos pobres nos creamos uno propio y pasamos de Verisign, total en el barrio me conocen y saben que soy de fiar.
mkdir /etc/apache2/ssl
RANDFILE=/dev/random openssl req $@ -new -x509 -days 365 -nodes -out /etc/apache2/ssl/apache.pem -keyout /etc/apache2/ssl/apache.pem
chmod 600 /etc/apache2/ssl/apache.pem
Apache tiene que escuchar por el puerto 443 (si tenéis firewall hay que permitir las conexiones), para ello añadir la siguiente línea en /etc/apache2/ports.conf
Listen 443
Solo queda configurar un VHost en Apache, para ello copiar el que viene por defecto por ejemplo
cp /etc/apache2/sites-available/default /etc/apache2/sites-available/ssl
y añadir/modificar para que escuche por el puerto 443 y use el certificado creado en el paso anterior, más o menos:
NameVirtualHost *:443 <VirtualHost *:443> ServerAdmin root@dominio.com ServerName www.dominio.com SSLEngine On SSLProtocol all #obliga a usar criptografia fuerte: Solo admite TLS y SSL3. SSLProtocol -all +TLSv1 +SSLv3 # Support only for strong cryptography SSLCipherSuite HIGH:MEDIUM:!aNULL:+SHA1:+MD5:+HIGH:+MEDIUM SSLCertificateFile /etc/apache2/ssl/apache.pem
Activar el nuevo site y recargar apache
a2ensite ssl
/etc/init.d/apache2 reload
PHP
Para que funcione PHP hay que copiar las librerías dentro del chroot, además para que futuras actualizaciones se realicen correctamente hay que enlazar las rutas antiguas a las correspondientes dentro del chroot.
Lo primero es instalar PHP5 (y algunos paquetes que, al menos a mi, me resultan útiles)
apt-get install php5 libapache2-mod-php5 php5-gd php5-ps php5-cli php-pear
Mover y enlazar las librerías de PHP
mv /var/lib/php5 /var/chroot/apache2/var/lib/php5 ln -s /var/chroot/apache2/var/lib/php5 /var/lib/php5 mkdir -p /var/chroot/apache2/usr/lib mv /usr/lib/php5/ /var/chroot/apache2/usr/lib ln -s /var/chroot/apache2/usr/lib/php5/ /usr/lib/php5
Con esto ya está funcionando PHP5, solo hay que reniciar Apache. Para probar que funciona se puede crear un archivo php con el siguiente contenido y llamarlo desde el navegador
<? echo phpinfo(); ?>
Una vez probado eliminar este archivo, la función phpinfo() suele usarse para atacar servidores.
MySQL
MySQL no se va a meter dentro del entorno chroot, personalmente considero que es bastante seguro tenerlo fuera y reporta pocos beneficios el enjaulado. Por ello lo único que hay que hacer es que el pid file y el socket sean accesibles desde dentro del entorno chroot, la solución es hacer que MySQL los cree dentro del directorio chroot.
Instalar mysql
apt-get install mysql-server-5.0 mysql-client-5.0 php5-mysql
Antes de nada hay que establecer la contraseña de root en mysql
mysql -u root mysql> UPDATE mysql.user SET Password = PASSWORD('pass') WHERE user = 'root'; mysql> FLUSH PRIVILEGES; mysql> quit;
Ahora hay que modificar el archivo /etc/mysql/my.cnf para que cree el socket y el pid file dentro del chroot
[client] port = 3306 socket = /var/chroot/apache2/var/run/mysqld/mysqld.sock [mysqld_safe] socket = /var/chroot/apache2/var/run/mysqld/mysqld.sock # * Basic Settings # user = mysql pid-file = /var/chroot/apache2/var/run/mysqld/mysqld.pid socket = /var/chroot/apache2/var/run/mysqld/mysqld.sock
Por último en Debian es aconsejable modificar el archivo /etc/mysql/debian.cnf para futuras actualizaciones (modificar socket)
# Automatically generated for Debian scripts. DO NOT TOUCH! [client] host = localhost user = debian-sys-maint password = 25aFDcXn5erfio4 socket = /var/chroot/apache2/var/run/mysqld/mysqld.sock [mysql_upgrade] user = debian-sys-maint password = 25aFDcXn5erfio4 socket = /var/chroot/apache2/var/run/mysqld/mysqld.sock basedir = /usr
Ejemplo
Un ejemplo de aplicación que use Apache, PHP y MySQL instalada con apt: phpmyadmin.
Por defecto la instalará en /var/www/, hay que moverla al chroot pero en caso de actualización puede suponer un problema. Para ello mover phpmyadmin dentro del chroot y enlazar los antiguos directorios a los nuevos dentro del chroot:
apt-get install phpmyadmin mv /etc/phpmyadmin /var/chroot/apache2/etc/ ln -s /var/chroot/apache2/etc/phpmyadmin/ /etc/phpmyadmin mkdir /var/chroot/apache2/usr/share mv /usr/share/phpmyadmin /var/chroot/apache2/usr/share mkdir /var/chroot/apache2/var/www/admin cd /var/chroot/apache2/var/www/admin/ ln -s ../../../usr/share/phpmyadmin/ phpmyadmin ln -s /var/chroot/apache2/var/www/admin/phpmyadmin/ /usr/share/phpmyadmin
TODO:
- No he conseguido ejecutar desde PHP binarios de Linux con exec. Sigo trabajando en ello, cualquier sugerencia es bien recibida.
Notas:
- Aunque las explicaciones estén realizadas sobre Debian puede aplicarse a cualquier otra distribución bien sea instalando las aplicaciones con el gestor de paquetes que lleve (apt en Debian) o, como se hizo toda la vida, compilándolos.
- Seguramente también funcione en otros sistemas operativos como los basados en BSD, puede que Solaris… en el caso de Windows no estoy totalmente seguro, al menos en el caso de mod_security no funciona según explica Kitai en este documento (pág. 5): Enjaular Apache con mod_security CHROOT
Si alguien lo prueba agradecería me lo haga saber para editar este punto. - También se puede realizar sobre Apache 1.3, aunque no lo he probado los pasos deberían ser los mismos.
- Obviamente chroot no es la solución a todos los males ni mucho menos, si quieres asegurar tu servidor web hay muchas configuraciones que hacer tanto en el propio sistema operativo, firewall, apache, php… un ejemplo:
Recomendaciones generales de seguridad
Referencias:
!!! esta vá en serio…¿o te estas quedando con nosotros ? ¡¡¡¡
Es un artículo que tenía en un antiguo blog y me parece interesante recuperar y compartir.
A diferencia del de Trasgu este es un blog personal así que iré poniendo de todo un poco, aunque la mayoría de entradas sean sobre rutas en bici también tocaré gastronomía, informática, puede que el Corrado y lo que surja.