Directorios virtuales con Reverse Proxy de Apache2 con Ubuntu Server

Visitas: 134  
Tiempo total: 2 días con 8:18:30 hrs  

En esta publicación explico los pasos necesarios para crear usuarios a nivel de sistema operativo, restringir acceso FTP sin acceso a la línea de comandos SSH (para que no pueda leer ningún documento externo), restringir ejecución de código PHP y hacer que su usuario tenga su propio entorno de ejecución PHP.

Problema inicial

Distintos administradores deben de tener una instancia en un servidor, se utiliza un mismo dominio web así que la solución son carpetas. Los administradores, curiosos, quieren tener acceso al sistema de archivos y base de datos. Dar solución al problema de acceso a la base de datos es simple, pero dar acceso al sistema de archivos no.

El dar acceso al sistema de archivos no se soluciona con crear un usuario ftp y limitarlo a su carpeta en el server, ya que es sabido que PHP se ejecuta en su defecto con el usuario “www-data”, así que el administrador (curioso), podrá crear un script que lea los otros directorios.

Maliciosamente un administrador podrá eliminar otros directorios o “instancias”. Si esto sucede todos me voltearan a ver como culpable e irresponsable. La solución es aislar a los “curiosos” en una caja segura, una “sandbox”.

Soluciones fallidas

La solución más simple es la mejor. Así que empecé con lo más simple:

1. Descarte la opción de crear usuarios FTP. Como ya lo mencione antes, todos ejecutarían los scripts PHP bajo el mismo usuario.

2. Directorios virtuales con la opción “Alias” de Apache2.

La sintaxis para utilizar Alias de Apache 2 es simple, y es la siguiente:

Alias /conspirador /home/conspirador
<Directory /home/conspirador>
Options SymLinksIfOwnerMatch
DirectoryIndex index.php
Require all granted
</Directory>

Y listo, el servidor Apache empezará a servir todos los archivos HTML que estén en el directorio del usuario “conspirador”, pero investigué bastante, bastante! Y no pude encontrar forma de aislar el usuario de ejecución PHP.

Mi servidor utilizar servidores virtuales, así que utiliza la siguiente sintaxis:

<VirtualHost dominio.com:80>
SuexecUserGroup “#{user-id}” “#{user-group}”

</VirtualHost>

Por lo tanto, para hacer funcionar Alias la sintaxis final debe ser la siguiente:

<VirtualHost dominio.com:80>
SuexecUserGroup “#{user-id}” “#{user-group}”

Include /etc/apache2/carpetas_virtuales/conspirador.conf
</VirtualHost>

En donde conspirador.conf contenía mi configuración para Alias. Esto me sirvió para utilizar la misma configuración tanto para HTTP como para HTTPS. El comando “SuexecUserGroup” no se puede utilizar adentro de las etiquetas <Directory>, así que el problema de seguridad persiste al utilizar Apache2 Alias.

Solución final: implementación de ProxyPassReverse

Reverse Proxy te permite agregar un servidor virtual y publicarlo en una carpeta virtual de un dominio existente. Esto soluciona el problema de usuario de ejecución PHP, separa la configuración PHP disponible para cada instancia y limita el alcance de los script PHP.

Paso 1: agregar usuario al sistema operativo

mkdir /home/conspirador
useradd -d /home/conspirador -s /bin/bash conspirador
sudo passwd conspirador

Paso 2: crear una Shell solo para usuarios FTP

nano /bin/ftponly

Contendrá el siguiente texto:

#!/bin/sh
echo “Esta cuenta solo dispone de acceso por FTP.”

Asignamos los permisos necesarios a la nueva shell:

sudo chmod a+x /bin/ftponly

Agregamos la shell ftponly a la lista:

sudo nano /etc/shells

Agregando el siguiente texto al archivo shells:

/bin/ftponly

Por último, asignamos el intérprete de comandos ftponly al usuario que hemos creado:

sudo usermod conspirador -s /bin/ftponly

Esto es necesario para no permitir que los usuarios curiosos logren navegar en directorios superiores al que le hemos asignado.

Paso 3: configurar archivos del nuevo servidor

La carpeta del usuario deberá de tener la siguiente estructura:

/home/conspirador/etc
/home/conspirador/fcgi-bin
/home/conspirador/public_html
/home/conspirador/tmp

El directorio etc deberá de contener el archivo php.ini, que deberá de tener la siguiente personalización:

(a) No permitir que se ejecute script php afuera del directorio del usuario:
open_basedir = /home/conspirador
(b) Cargar todas los archivos temporales y de sesión en la carpeta tmp del usuario:
upload_tmp_dir = /home/conspirador/tmp
session.save_path = /home/conspirador/tmp
(c) Restringir el tamaño de carga de archivos:
upload_max_filesize=8M
post_max_size=8M

La carpeta fcgi-bin deberá de contener el archivo phpX.fcgi (dependerá de la versión php que quieras ejecutar):

#!/bin/bash
PHPRC=$PWD/../etc/phpX
export PHPRC
umask 022
export PHP_FCGI_CHILDREN
PHP_FCGI_MAX_REQUESTS=99999
export PHP_FCGI_MAX_REQUESTS
exec /usr/bin/php-cgiX

Listo, eso es todo. Lógicamente deberás de tener experiencia en hacer funcionar PHP con FCGI.

Paso 4: asignación de permisos chmod

La instrucción chmod de Linux permite modificar los permisos de lectura, escritura y ejecución de un archivo o carpeta. La sintaxis es la siguiente:

Chmod {usuario} {grupo} {otros}

  • Usuario: que permiso sobre el archivo tiene el dueño del mismo.
  • Grupo: que permiso sobre el archivo tiene cualquier usuario que pertenezca al mismo grupo del archivo.
  • Otros: comúnmente se le llama “mundo”. Es decir, cualquier usuario que tenga acceso al sistema operativo.

Para los tres tipos de permiso, los posibles valores son:

  • R: read con un valor de 4
  • W: write con un valor de 2
  • X: execute con un valor de 1

Por ejemplo, si queremos que el usuario dueño del archivo pueda leer, modificar (write) y ejecutar scripts de un archivo, le asignamos un valor de 7.

Si queremos que los usuarios que pertenecen al mismo grupo puedan solo leer y ejecutar pero no modificar, le asignamos el valor de 5.

Si queremos que cualquier otro usuario no pueda ni leer, ni modificar ni ejecutar, le asignamos un valor de 0.

Entonces, el comando chmod debe de ser: “chmod 750 archivo.txt”.

Paso 5: configuraciones de seguridad de acceso y lectura de archivos

El siguiente comando le asigna el valor chmod 755 a las carpetas y 664 a los archivos dentro del directorio del usuario:

find /home/conspirador/ -type d -print0 | xargs -0 chmod 0755
find /home/conspirador/ -type f -print0 | xargs -0 chmod 0664

Hacemos que el usuario de tmp y public_html tenga todos los accesos, el grupo pueda leer y ejecutar y todos los demás no tengan ningún tipo de acceso:

chmod 750 /home/conspirador/tmp
chmod 750 /home/conspirador/public_html

Los mismos permisos son necesarios para la carpeta principal del usuario, esto permite que si alguno de los demás usuarios tienen acceso SSH o vía PHP (por algún error, ya que eso ya lo hemos restringido), los demás no podrán tener acceso al sistema de archivos de nuestro usuario:

chmod 750 /home/conspirador

Con los siguientes permisos hacemos que todos puedan leer y ejecutar los archivos dentro de etc y fcgi-bin, pero no puedan modificarlos.

chmod 555 /home/conspirador/etc/ -R
chmod 555 /home/conspirador/fcgi-bin/ -R

Es necesario denegar la edición de estos archivos, entre los comandos que no se deben de modificar están “open_basedir” que es lo que limita la ejecución de PHP, está también el límite de carga de archivos y la versión de PHP.

Existe otra vulnerabilidad: el usuario simplemente puede iniciar sesión FTP, cambiar el nombre de las carpetas etc y fcgi-bin y crear otras nuevas, con una configuración diferente (eso es lo que yo como todo curioso intentaría hacer). Para esto, hacemos intocables los directorios etc y fcgi-bin con los siguientes comandos:

chattr +i / home/conspirador/etc
chattr +i / home/conspirador/fcgi-bin

Por último, hacemos dueño al usuario y grupo “conspirador” de todos los archivos dentro de su carpeta con el siguiente comando:

sudo chown conspirador:conspirador /home/conspirador –R

Paso 6: creamos el servidor virtual que servirá los archivos del usuario

Para evitar crear una interface local virtual y abrir distintos puertos (lo cual hace inseguro el servidor), puedes utilizar la dirección loopback del servidor, esta es: 127.0.0.0/8, esto significa que tienes desde la dirección 127.0.0.1 a 127.255.255.254, todas estarán escuchando el puerto 80.

Como usuario root, podemos ver el ID del usuario conspirador con el siguiente comando:

nano /etc/passwd

Para este ejemplo, supongamos que el tanto el id como grupo es 6000. La configuración del servidor virtual será la siguiente:

<VirtualHost 127.0.0.1:80>
SuexecUserGroup “#6000” “#6000”
ServerName conspirador.local
ServerAlias conspirador.local
DocumentRoot /home/conspirador/public_html
ErrorLog /var/log/conspirador_error_log
CustomLog /var/log/conspirador_access_log combined
ScriptAlias /cgi-bin/ /home/conspirador/cgi-bin/
DirectoryIndex index.html index.htm index.php
<Directory /home/conspirador/public_html>
Options -Indexes +IncludesNOEXEC +SymLinksIfOwnerMatch +ExecCGI
allow from all
AllowOverride All Options=ExecCGI,Includes,IncludesNOEXEC,Indexes,MultiViews,SymLinksIfOwnerMatch
Require all granted
AddType application/x-httpd-php .php
AddHandler fcgid-script .php
FCGIWrapper /home/conspirador/fcgi-bin/phpX.fcgi .php
</Directory>
RemoveHandler .php
</VirtualHost>

El código anterior deberás de colocarlo en la carpeta de sitios disponibles de Apache2 “/etc/apache2/sites-available”. Para activarlo, usa el siguiente comando:

a2ensite conspirador.conf

El sitio no afectará tu servidor público, es decir, dominio.com. Para verificar que funcione, puedes colocar un archivo index.php que ejecute cualquier script y que muestre un resultado, luego, descarga el código HTML con el siguiente comando:

wget http://127.0.0.1

Si algo falla, deberás de revisar detenidamente el error y los permisos que has asignado al sistema de archivos de usuario. Si quieres volverá deshabilitar el sitio, usa el comando:

sudo a2dissite conspirador.conf

Paso 7: publicar la carpeta virtual

Para eso, únicamente debes de agregar las siguientes líneas al archivo de configuración del servidor virtual de tu domino público:

ProxyPass /conspirador http://127.0.0.1:80
ProxyPassReverse /conspirador http://127.0.0.1:80

Conclusión

Con esto, cada instancia estará en una sandbox y cada uno será responsable de su propio sistema de archivos y base de datos. Para el acceso FTP utilicé ProFTP, que por defecto asigna a los usuarios a su propia carpeta.

El único problema de seguridad es la conexión SFTP utilizando SSH, debería de estar habilitado pero al negar al usuario acceso a la línea de comandos bash, esta opción se deshabilita. Es una mejor decisión no comprometer el sistema de archivos del servidor, que la conexión FTP del usuario externo. La solución al acceso SFTP quedará pendiente, la publicaré en otra entrada.


Para recibir boletines de información, por favor escribe tu correo electrónico:

Por favor ingrese un correo electrónico valido.
Registrado correctamente!