Además de las directivas mencionadas en la publicación anterior, existen algunas otras que permiten un control mucho más “especifico” sobre características de seguridad en el servidor web Apache, el objetivo de esta publicación es intentar explicar como funcionan dichas directivas y algunos “tips” de seguridad que normalmente se suelen aplicar para proteger la infraestructura del servidor web y las aplicaciones que en él se alojan.

Ocultación del Server Header:

Se trata de algo “básico” que siempre debe de tomarse en cuenta, ocultar cualquier tipo de información sensitiva sobre el servidor o sus aplicaciones. En este caso la directiva encargada de ocultar información que el servidor web incluye en los HTTP Headers es ServerSignature Cuando el valor de esta directiva es “On” el servidor web arrojará información sobre el servidor web cuando la petición de un cliente da como resultado un error HTTP 3XX, 4XX o 5XX, esta información normalmente incluye el nombre del servidor, la versión que se encuentra en ejecución, el tipo de servidor (unix, windows) y si existe definido un “ServerName” este valor también aparecerá. Afortunadamente, este valor en servidores Apache 2.2.X viene con un valor por defecto a “Off” Por lo tanto normalmente no es necesario establecer manualmente su valor a “Off” en el fichero de configuración (pero nunca esta de más).

Por otro lado, todas las respuestas a peticiones HTTP llevadas a cabo por un cliente, siempre obtienen como respuesta un conjunto de campos que contienen “metadatos” con información sobre el estado de la petición y otros detalles que para un atacante podrían resultar interesantes. En concreto uno de los HTTP Headers que puede dar mayor información a un atacante es el campo “Server” el cual puede incluir información sobre el servidor web y el sistema operativo en donde se esta ejecutando, por ejemplo, el siguiente listado corresponde a una respuesta HTTP emitida por un servidor Apache:

HTTP/1.1 200 OK

Date: Mon, 20 Feb 2012 22:48:04 GMT

Server: Apache/2.2.22 (Unix)

Last-Modified: Sat, 20 Nov 2004 20:16:24 GMT

ETag: «981d62-2c-3e9564c23b600»

Accept-Ranges: bytes

Content-Length: 44

Content-Type: text/html

Como puede apreciarse, el header “Server” ha retornado información sensitiva sobre el servidor web. Para evitar esto, se suele utilizar la directiva ServerTokens con el valor “ProductOnly” de esta forma se eliminará información sensitiva de este campo en las respuestas emitidas por el servidor, tal como se enseña a continuación:

HTTP/1.1 200 OK

Date: Mon, 20 Feb 2012 22:39:43 GMT

Server: Apache

Last-Modified: Sat, 20 Nov 2004 20:16:24 GMT

ETag: «981d62-2c-3e9564c23b600»

Accept-Ranges: bytes

Content-Length: 44

Content-Type: text/html

Como puede apreciarse, se ha suprimido “casi” toda la información relacionada con el servidor web, pero, como se quita el hecho de que salga el tipo de servidor web que emite las respuestas. Para ello, se utiliza el modulo ModSecurity (esto se verá en la próxima publicación)

Especificar usuarios con privilegios limitados

Normalmente cuando se inicia Apache, los parámetros “User” y “Group” tienen el valor por defecto “nobody” al igual que otros servicios conocidos tales como el servidor de correo sendmail y otros. Por este motivo siempre es una buena practica (altamente recomendada para especialmente aquellos servicios expuestos en internet) crear un usuario y grupo con privilegios limitados para que estos sean utilizados en la ejecución del servicio.

NOTA:

En versiones de Apache 2.4 es necesario cargar el modulo mod_unixd para que funcionen correctamente las directivas User y Group, para ello incluir en el fichero de configuración la siguiente linea:

LoadModule unixd_module modules/mod_unixd.so

Limitar el acceso a directorios utilizando la directiva <Directory>

La directiva <Directory> permite declarar el acceso a directorios disponibles en la máquina y a los que el servidor web puede acceder y/o manipular. Una buena practica es declarar el directorio donde se encuentran alojadas las aplicaciones web y no permitir que Apache pueda acceder a directorios que se encuentran por fuera de dicho directorio

NOTA: El mismo resultado puede conseguirse con ficheros .htaccess en cada directorio, sin embargo este enfoque no es recomendable (ni mantenible) tal como se verá más adelante.

por ejemplo:

DocumentRoot «/opt/apache2.2.22//htdocs»

<Directory />

Order Deny,Allow

Deny from all

Allow from 192.168.1.0/24

</Directory>

<Directory /webapps>

Order Allow,Deny

Allow from all

</Directory>

El ejemplo anterior simplemente indica que el directorio raíz de Apache será “/opt/apache2.2.22/htdocs” y posteriormente con la directiva <Directory /> se esta estableciendo un modelo restrictivo dado que el orden de los permisos será “Denegar todo y posteriormente permitir solamente aquellas instrucciones con la directiva allow” en donde solamente se permitirá el acceso a peticiones cuyo origen sea una dirección IP en el rango de 192.168.1.0, lo que evidentemente se puede afinar al gusto del administrador utilizando incluso expresiones regulares. Además, el hecho de establecer las directivas Options None y AllowOverride None desactivará todas las opciones en los directorios (partiendo de la raíz) y en la segunda directiva <Directory «/webapps»> se permite el acceso a todos los contenidos que se encuentren en el directorio webapps pero respetando las directivas que se han aplicado en el directorio padre, por lo tanto en este sencillo ejemplo, solamente se podrá acceder a la raíz y al directorio “webapps” cuando se soliciten dichos recursos desde una dirección IP valida en la instrucción “allow

Limitar las opciones disponibles en cada directorio

En el ejemplo anterior se limitaba demasiado el acceso, algo que en la practica probablemente es poco viable, en tal caso, es frecuente utilizar opciones de la directiva <Directory> algunas de estas opciones recomendadas son:

<Directory />

Options -Indexes

Options -Includes

Options -ExecCGI

Options -FollowSymLinks +SymLinksIfOwnerMatch

AllowOverride None

</Directory>

<Directory /web>

Order Allow,Deny

Allow from all

</Directory>

Con las lineas de configuración anteriores se define lo siguiente:

En primer lugar todas las opciones de la directiva se aplican directamente sobre el documento raíz, con lo cual se aplicarán a los subdirectorios. Por otro lado, en la primera linea, se establece que no se pueden llevar cabo exploraciones de ficheros y directorios de forma directa en alguno de los directorios del servidor web, cualquier intento de hacer una acción como estas, producirá un error HTTP 403 (Forbidden) con lo cual es necesario especificar el recurso al que se desea acceder. Las opciones –Includes y –ExecCGI limitan en primer lugar los “Server Side Includes” (SSI) de los que se hablará próximamente y por otro lado, se limita la ejecución de ficheros CGI. Nótese que se ha utilizado el comodín (-) en todos los casos para excluir dichas opciones, en el caso de que se deseen incluir se utiliza el comodín (+)

Adecuación de ficheros .htaccess

Los ficheros .htaccess son elementos que permiten incluir cualquier tipo de directiva que se puede definir en el fichero de configuración httpd.conf sin embargo aplican al nivel de cada directorio en el que se encuentran ubicados (también en sus subdirectorios). Además de esto, los subdirectorios heredan las características declaradas en el fichero que se encuentra en el directorio padre y pueden sobreescribirlas si es oportuno. Por otro lado, estos ficheros son “invisibles” es decir, normalmente los servidores web modernos están configurados para simplemente ignorarlos. El uso de este tipo de ficheros, permite a un administrador tener un control muy fino de todos los directorios que tiene alojados en su servidor web. Sin embargo, algunos administradores opinan que en realidad, esta flexibilidad puede ser posteriormente un problema para la seguridad y la integridad de la estructura de ficheros dado que en la medida de que el número de directorios aumenta (por ejemplo un servidor web con aplicaciones grandes) el mantenimiento de las normas de seguridad que se deberían aplicar puede ser demasiado complejo y evidentemente, en la medida que la complejidad aumenta, las probabilidades de “agujeros” y malas configuraciones es mayor. En ocasiones se aconseja utilizar la directiva <Directory> en lugar de usar este tipo de ficheros y para hacerlo se hace utilizando la directiva <Directory> y la opción “AllowOverride None” por ejemplo:

<Directory />

AllowOverride None

</Directory>

En el caso de que se desee seguir aprovechando las ventajas de este tipo de ficheros (o de que se necesite la opción de Override habilitada), si que se recomienda cambiar el nombre del fichero .htaccess con la finalidad de que este no pueda ser descargado y/o modificado por un atacante, esto se hace con el uso de la directiva AccessFileName por ejemplo

AccessFileName .httpseguro

<Files ~ “^\.ht”>

Order allow,deny

Deny from all

Satisfy all

</Files>

Con lo anterior, simplemente se ha declarado un nuevo nombre para los ficheros .htaccess además de que se ha declarado una regla de seguridad para todos los ficheros que comienzan con “.ht” desde el directorio raíz del servidor web. Como se puede apreciar para aplicar estas instrucciones se ha utilizado una expresión regular simple.

NOTA: En el caso de que exista algún conflicto entre la directiva <Directory> y alguno de los ficheros .htaccess la directiva contenida en el fichero de configuración tendrá más peso y será la que se aplique al final.

Desactivar módulos innecesarios

La simplicidad es una característica propia de los sistemas con unos buenos niveles de seguridad y en el caso de Apache, siempre es recomendable tener disponibles solamente los módulos que se van a necesitar, ni más ni menos. En este orden de ideas es recomendable analizar el fichero de configuración y eliminar cualquier modulo que no sea necesario para las aplicaciones web que se encuentran alojadas en el servidor web o para cualquier otro servicio que preste el servidor web. Para optimizar este proceso, se puede usar el comando grep para buscar todas las declaraciones de módulos y posteriormente eliminar aquellos que sobran

>grep LoadModule httpd.conf

Definir unos tiempos de Timeout óptimos

Cuando un servidor web permite que las aplicaciones recibidas por un cliente tarden demasiado en procesarse (unos pocos minutos, ya puede considerarse un tiempo inaceptable) se puede presentar una situación de “Denegación de Servicio” que puede ser aprovechada por uno o varios atacantes, por ese motivo siempre es recomendable limitar el tiempo que el servidor web empleará para procesar cada petición recibida del cliente. Para ello se suele utilizar la directiva “Timeout” con un valor un poco más pequeño que el valor por defecto “300”, por ejemplo 45 segundos será más que suficiente.

Timeout 45

Con lo anterior, el tiempo máximo que empleará el servidor para procesar una petición del cliente serán 45 segundos.

Limitar el tamaño de las peticiones

Del mismo modo que ocurre con la directiva “Timeout” es posible que la petición de un cliente tenga un tamaño demasiado grande y generar una condición para realizar un ataque de denegación de servicio, en este orden de ideas es posible utilizar la directiva “LimitRequestBody” para establecer el tamaño máximo de las peticiones.

LimitRequestBody 1048576

Con lo anterior, el tamaño máximo admitido para una petición será de aproximadamente 1 MB. No obstante, tener presente que si alguna aplicación web alojada en el servidor tiene algún tipo de componente de FileUpload donde el cliente puede transferir archivos al servidor, este valor debería ser mayor a un 1MB (a menos que se intente limitar el tamaño de los ficheros a este tamaño).

Limitar el numero de usuarios concurrentes.

Es posible ajustar a un nivel bastante fino el nivel de concurrencia que tendrá el servidor web usando algunas directivas disponibles para tal objetivo. En concreto la directiva MaxClients indica el número máximo de usuarios concurrentes que admitirá el servidor, en el caso de que este valor sea demasiado alto pueden existir problemas de memoria y rendimiento general, por lo tanto es importante asignar un valor apropiado en esta propiedad.

Sin embargo, este punto es complejo y consta de varias directivas disponibles en el servidor web, por lo tanto es importante tener presente. A continuación se explica el funcionamiento de dichas directivas:

StartServers: Indica el numero de procesos hijo (pre-fork) que apache creará al iniciar el servidor web, estos procesos, simplemente estarán a la espera de nuevos clientes.

MinSpareServers: Indica el número de procesos hijo mínimo (pre-fork) que debe tener disponibles el servidor en todo momento. En el caso de que este número sea menor al número total de procesos hijo creados (algo que puede ocurrir con bastante frecuencia en el caso de aplicaciones web muy concurridas) el servidor web se encargará de forma automática de crear estos procesos hasta que se alcance nuevamente este valor mínimo (Apache generará cada proceso hijo a un ritmo de 1 por segundo para evitar cualquier tipo de interbloqueo) el valor por defecto es 5.

MaxSpareServers: Funciona igual que MinSpareServers, sin embargo en este caso, esta propiedad establece el tope máximo de procesos hijo disponibles en el servidor web, este valor, evidentemente debe de ser mayor que el valor establecido en la directiva MinSpareServers. El valor por defecto es 10.

MaxRequesPerChild: Como su nombre lo indica, simplemente define el número de peticiones que un proceso hijo puede atender durante su ciclo de vida total, cuando este número se alcanza, el proceso debe finalizar y debe ser correctamente removido. En el caso de que el valor de esta propiedad sea 0 no habrá ningún limite. Esta situación no es aconsejable, ya que si el proceso no llega a eliminarse nunca, si en él existen problemas de memoria, este proceso seguramente consumirá recursos y será necesario eliminarlo manualmente. El valor por defecto de esta propiedad es 1000.

ThreadsPerChild: Indica el numero de Threads que se asignarán al proceso hijo en el momento de su creación. Este número es fijo y no varia durante el ciclo de vida del proceso, por este motivo es muy importante establecer un número lo suficientemente grande como para poder atender todas las peticiones que se lleven a cabo. Esta directiva puede tener dos valores por defecto dependiendo del modo de ejecución si se usa un MPM “winnt” o si se usa un MPM “worker”, en el primer caso el valor por defecto es 65 en el segundo caso el valor es 25. (Sobre MPM se verá más adelante).

ThreadLimit: Indica el número máximo que pueden especificarse en la directiva ThreadsPerChild. El valor de esta propiedad debe de ser muy “medido” ya que si se establece un valor muy grande, posiblemente se pueda producir un desperdicio de memoria, ya que se asignará más de que la realmente se utilizará por la directiva ThreadsPerChild. El valor por defecto de esta directiva es 1920 en el caso de usar MPM winnt y de 64 en el caso de usar MPM worker.

Los valores de estas propiedades vienen restringidos directamente en el código del servidor web a 20000 para MPM worker y 15000 en winnt, esto para evitar que se asignen valores demasiado grandes que posteriormente el sistema no podrá tratar.

NOTA: Un “fork” en informática no es más que un subproceso dependiente de un proceso padre que copia sus mismas características y se ejecuta de manera concurrente. La técnica de “fork” permite que un proceso padre pueda crear tantos hijos como sean necesarios para procesar las peticiones de varios clientes sin que con ello exista algún tipo de corrupción de memoria o interbloqueo en el proceso padre, ya que si por algún motivo, uno de los “fork” (proceso hijo) tiene problemas para procesar alguna petición, solamente afectará a dicha petición y no al servicio en general. Esta característica se encuentra presentes en prácticamente todos los servidores web y cualquier proceso que reciba y procese peticiones como por ejemplo sockets “raw” que atiendan a varios clientes de forma concurrente.

Los valores anteriormente descritos podrían tener la siguiente configuración

<IfModule mpm_worker_module>

StartServers 2

MaxClients 150

MinSpareThreads 25

MaxSpareThreads 75

ThreadsPerChild 25

MaxRequestsPerChild 100

</IfModule>

Como se puede ver, se ha usado la directiva <IfModule> la cual permite consultar si un MPM concreto se encuentra cargado, en este caso se consulta por el MPM worker (sistemas basados en UNIX).

En la próxima publicación, más sobre seguridad en servidores web Apache.