domingo, 3 de junio de 2018

Hardening de tus servidores GNU/Linux utilizando GLAMP

/* DISCLAIMER
En este post me centro en cómo configurar nuestros servidores para que soporten una gran carga de trabajo y con una velocidad bastante aceptable sin que caiga nuestra web o cualquiera de nuestros servidores.

Se han repasado algunos de los conceptos y archivos de configuración que se deben tocar en nuestros servidores GLAMP {GNU/Linux, Apache, MySQL || MariaDB y PHP. Con esta configuración demuestro que puedes llegar a soportar 3 veces más carga que con un servidor GLAMP montado por defecto y con todo recién instalado.

Esto además de soportar una carga alta de trabajo, nos aporta una mayor seguridad en nuestros servidores dado que la disponibilidad es seguridad. Por esta razón, cuando tenemos que tocar un servidor web, puede que estemos ante uno de los entornos más complejos a administrar, ya que su exposición es bastante alta.

Para lograr todo lo que se menciona, se tratará de tomar medidas de seguridad por oscuridad, modificación de configuraciones por defecto, optimización de recursos en Apache, PHP y MySQL || MariaDB. Se aplicarán módulos de caching para las pruebas de estrés que realizaremos con UfoNet y la herramienta de Apache2-utils ab y comprobar que se ha realizado una configuración bastante eficaz.

Sobre el por qué se ha escogido Apache en lugar de otros servidores, también se comentará en este post, viendo cómo opera cada uno en cuanto a velocidad, rendimiento, características, en qué entornos es mejor utilizar uno u otro, en por qué hay archivos con configuraciones por defecto {¿inseguras?} etc.

Recordar que se está trabajando con Debian 8, aunque todo lo comentado es igualmente aplicable para todas las ramas GNU/Linux.

Por último mencionar que si aplicáis cualquiera de estas configuraciones, es aconsejable realizarlas primero en modo local en lugar de entornos de producción, puesto que dependerá de otros aspectos de tu servidor. Por ejemplo ¿utilizas un panel de control tipo Plesk o Cpanel? Pues cosas como esa pueden interferir, generando un verdadero dolor de cabeza para cualquier administrador de sistemas.

*/

Ya vimos en el post de "Comprobando la seguridad de tus servidores" algunas debilidades, misconfiguration o incluso algunas vulnerabilidades en nuestro servidor Debian 8 con un servidor GLAMP sobre el que se montó un Wordpress. Si no recordáis algo de esa entrada, os recomiendo que la tengáis en una pestaña a parte o incluso que la releáis sino lo habíais hecho.




Debe quedar claro, que un servidor web, no es solamente la web con su código de programación, es todo un conjunto y se puede ver afectado hasta por cómo se haya realizado la instalación. Así que vamos a comenzar desde la base, desde la misma instalación.
Partición de disco recomendada
Los más recomendado es utilizar el sistema de archivos ext4, ya que ext3 te puede recuperar los datos ante pérdidas pero si te equivocas y borras algo por error, ta va a ser imposible recuperar esos datos. Si queréis conocer un poco mejor los sistemas de archivos de Linux os dejo este enlace a la Universidad de Valencia.


En The Debian HandBook explican bastante bien para qué sirve cada método de instalacción. Para nuestro caso, como se dice en el libro, el método más recomendado es el de realizar la instalación por separado de /home, /usr, /var y /tmp ya que el usuario solamente va a poder trabajar con /home y /tmp, siendo estas las particiones que va a poder llenar, dejando las demás separadas y que nuestro server no tenga problemas de memoria, algo que puede afectar al rendimiento.
Os recomiendo enormemente que os leáis The Debian Handbook, os va a servir de utilidad, además, aprovecho y os dejo otra opción de realizar la instalación de vuestro sistema que también se comenta en el libro, que es la instalación de LVM, algo que -entre muchas de las opciones que nos brinda- nos va a permitir redimensionar una partición en caliente sin reinstalar.


Cualquiera de las 2 opciones son buenas opciones para nuestro servidor. Yo personalmente me suelo decantar por la primera en lugar de utilizar LVM, aunque soy consciente de que puede dar también un buen rendimiento LVM. Eso como veias mejor vosotros y lo que mejor sepáis administrar.

Optimizando Apache y sus módulos multiproceso en Worker {MPM}

Podemos ver el modo en el que se está ejecutando nuestro Apache con el comando apachectl -V y ver si se ejecuta en Worker, Prefork o Event. También podemos ver los modos que estén activos en nuestro server dentro de /etc/apache2/mods-enabled/. Veamos algunos aspectos a tener en cuenta de estos modos multiproceso de Apache.

Muy interesante Apache 2 y 2.4 en Debian 8. Además, para nuestros servidores web con GLAMP es muy interesante el multiproceso {MPM} permitiendo un control dinámico de los procesos según la carga bajo demanda. Todo esto lo vamos a configurar en /etc/apache2/apache2.conf, le daremos mucha caña a este fichero.


Los modos MPM que tenemos en Apache son, como se ha dicho:

  • Prefork. Es el que está por default. Procesos hijo,mod_php. Es más estable que Worker y es más compatible con más módulos o software. Presenta una mayor capacidad de aislamiento que Worker si hubiese un problema con una petición respecto al resto de los procesos hijo.
  • Worker. Lanza procesos hijos e hebras por hijo. Aquí tenemos a PHP ejecutándose como fastCGI. Cierto es que hay un menor consumo de memoria. Un pero muy importante es que si un hilo falla, afectará al resto, siendo eso un problema más que evidente.
 


Tiramos de apachectl fullstatus y veremos el estado de nuestro servidor y el MPM que se está utilizando. Muy importante comprobar los cambios en el estado del servidor con forme se van realizando cambios y mientras hacemos pruebas de estrés al servidor.

Si lo tenemos controlado y encontramos un funcionamiento irregular, nos será más fácil detectar qué puede estar ocasionando ese funcionamiento incorrecto.
Existen unos aspectos generales en la configuración de Apache que si los entendemos, podremos saber qué tocar para un funcionamiento eficiente del servidor.
  • TimeOut. Campo que recoge los segundos antes de que se cancele una conexión debido a un fallo de conexión.
  • Keepalive. Campo de las conexiones persistentes y que se recomienda tenerlo en "On" para poder permitir así, múltiples peticiones sobre la misma conexión TCP. Para conexiones HTTP de larga duración es lo má recomendado. Este campo funciona de tal manera que cuando se conecta a la web, se la baja entera con todas sus imágenes, css y todo y espera el número de segundos del Keepalive. 
  • MaxKeepAliveRequest. Es el campo que limita el número de peticiones permitidas por conexión KeepAlive. Si lo ponemos a 0, lo que estamos indicando es que se permiten conexiones ilimitadas. Lo ideal es establecer un número alto. Pongamos unos 700.
  • KeepAliveTimeout. Es el campo que refleja los segundos que Apache esperará peticiones antes de poder cerrar una conexión persistente. En caso de recibir una petición, se aplica la directiva Timeout para el cierre de la conexión. Evidentemente, cuanto mayor valor le demos, mayor será el número de procesos del servidor que estarán ocupados esperando conexiones con clientes no activos. Lo ideal son unos 3-5 segundos.

Configurando Prefork y Worker
Antes de explicar cada uno, decir que existe un tercero que es Event, pero yo no he usado mucho y no me atrevería a decir nada de Event sin esa experiencia tocándolo, por lo que estoy abierto a leer vuestras sugerencias. No obstante, os dejo aquí algunas de las características de Event y sus diferencias con Worker mejorando las conexiones KeepAlive.



En /etc/apache2/mods-enabled podemos ver los modos que tenemos activos, y entrando a, en este caso a mpm_prefork.conf, podremos configurar algunos campos que también deberemos de conocer y entender para saber qué tocar y por qué.
  • StartServers. Número de procesos hijos que se crean en el arranque.
  • MinSpareServers. Número ínimo de procesos hijo esperando peticiones.
  • MaxSpareServers. Número máximo de procesos hijo esperando peticiones.
  • MaxRequestsWorkers. Número máximo de procesos hijo permitidos al arranque.
  • MaxConnectionsPerChild. Número máximo de peticiones de procesos hijo.
Esto es por parte de Prefork, que recordemos que es multiproceso con procesos hijo y sin hebras. En Worker que es multiproceso, con procesos hijo y con hebras, tenemos los siguientes campos. Recuerdo que deberemos instalar el MPM de Worker ya que no lo tendremos instalado por defecto.

  • MinSpareThreads. Número mínimo de hebras en espera para atender peticiones.
  • MaxSpareThreads. Número máximo de hebras en espera.
  • ThreadLimit. Límite estricto del número de hebras del servidor.
  • ThreadsPerChild. Número de hebras creadas por cada proceso hijo.
  • ServerLimit. Límite estricto de procesos hijo activos posibles. Deber ser mayor o igual que MaxClients o MaxRequestsWorker en función de la versión utilizada.
Otras opciones que pueden ser interesantes configurar en los archivos de configuración de Apache para lograr una mayor seguridad mediante técnicas de seguridad por oscuridad. Esto hará que mucha información los atacantes no puedan lograr acceder a información y sacar información del servidor web Apache.



Si recordáis el post de Comprobando la seguridad tu servidor, hubo un apartado en el que analizamos si se utilizaba el método TRACE. En el archivo /etc/apache2/conf.d/security comprobaremos si está en Off.


En el archivo /etc/apache2/security.conf también podemos configurar que el campo ServerTokens esté en Prod y ServerSignature esté en Off.


En el archivo .htaccess de nuestro sitio, podemos añadir el campo Options con -Indexes para evitar así los listados en cualquier directorio de nuestro sitio. En este artículo sobre cómo evitar listados de directorios -algo muy importante a proteger para evitar fugas de información en fases de fingerprinting- se da más información. Es un artículo de lectura muy recomendable.


Otra opción que hay que tocar es el valor del Timeout ya que, dependiendo el modo {prefork, worker o event}, os vendrá con 120,200 ó 300 segundos. Esto es una burrada y este valor hay que bajarlo a 30,20 ó 15 segundos como mucho. Pensad que un navegador que esté 300 segundos sin responder no es normal, son 10 segundos y la gente ya se desespera y da en la "X", así que no esperes tanto a emitir ese Timeout .
En cuanto al KeepAlive, en muchos servidores vendrá a 30 ó 15 segundos, lo que también es algo totalmente inútil, puesto que tener a un equipo 15 segundos esperando en la web cuando ya tiene toda la web bajada, es algo que consumer recursos, y si ese equipo está consumiendo esos recursos, dejá a otros sin ellos, por lo que pierdes disponibilidad. Si tienes Apache en Prefork, déjalo en 5 segundos como mucho.
Y como siempre digo, cuidado con el MaxClients. Aquí hay gente que dice de todo. Yo lo tengo en un número alto, y tened en cuenta que en prefork, el valor por defecto es 256, pero si queréis un valor mayor, tendréis que tocar el campo ServerLimit.

La razón por la que he decidido hacer esto sobre Apache en lugar de Nginx es, en primer lugar, porque es lo que más toco y porque cuando entró con Apache 2.4 con su entrada y salida asíncrona, proxy inverso y temas nativos de caching, me enamoré como Shakira. Es cierto que Nginx es muy recomendable y que para contenido estático es una solución muy buena, pero creo que hay que controlar bien los problemas en cuanto a rendimiento que te puede dar un Apache y saber cómo configurarlo, ya que muchas de las configuraciones no llevan ni 5 minutos. Aún así, si queréis conocer más sobre Apache y Nginx, os recomiendo este podcast donde se comentan varios puntos muy interesantes.



Sistemas de "caching" y optimización de PHP

A mí me gusta Memcached, nos será muy útil para cachear todo lo cacheable de nuestro server y obtener un mejor rendimiento de nuestro server con Memcached y X-Cache. Primero vamos con su instalación.

Instalación

El comando de instalación es sencillo, eso sí, desde su {esto no debería recordarlo, pero por si acaso }.

Con el comando php --ri y el módulo //yo he puesto memcache, pero podríais escribir xcache por ejemplo veremos si están cargados los módulos. Aquí podemos ojear cómo está nuestro sistema de caching con memcached.

Tener este sistema de caching montado con memcached nos va a ayudar a obtener un mejor rendimiento de nuestro servidor, aportando una mejor disponibilidad de los recursos.

Ahora, pasando a PHP, comentar que PHP 7 trae unas mejoreas notables en cuanto rendimiento y memoria.

Aquí os dejo un gráfico sobre una comparativa entre PHP5 y PHP7. Para más información, es muy interesante que reviséis esta referencia donde se realiza una comparativa en profundidad.



La diferencia es importante, por lo que casi que es obligatorio que tiremos hacía PHP7, ya que nuestro server lo notará. Tened en cuenta que cuanto mayor rendimiento y menor uso de memoria, mejor disponibilidad ofreceremos a nuestros clientes.

¿Cómo realizar la migración? En la misma web de PHP se os explica de una manera bastante sencilla. También me parecen muy interesantes las nuevas características que ofrece PHP7.

Otro aspecto importante será considerar las funciones PHP que sería interesante que deshabilitemos por cuestiones de seguridad. Si nos vamos a /etc/php5/apache2/php.ini y nos vamos al apartado de disable_functions encontraremos unas funciones por defecto ya añadidas.
pcntl_alarm,pcntl_fork,pcntl_waitid,pcntl_wifexited,pcntl_wifstopped, pcntl_wifsignaled, pcntl_wexitstatus, pcntl_wtermsig,pcntl_wstopsig,
pcntl_signal, pcntl_signal_dispatch, pcntl_get_last_error,pcntl_strerror,
pcntl_sigprocm    ask, cntl_sigwaitinfo,               pcntl_sigtimedwait,
pcntl_exec, pcntl_getpriority, pcntl_setpriority,

Estas son las funciones que están deshabilitadas por defecto en muchos servidores, yo además añado un bloque extra con otras funciones que, en caso de permitirlas, puede suponer un fallo grave de seguridad. El bloque extra es el siguiente:
system, exec, pasthru, shell, shell_exec, popen, pclose, proc_nice, 
proc_terminate, proc_get_status, proc_close, pfsockopen, leak,
apache_child_terminate, posix_kill, posix_mkinfo, posix_setpgid,
posix_setsid, posix_setuid, escapeshellcmd, escapeshellarg, phpinfo,
proc_open, show_source, passthru.
Aquí os dejo el archivo de configuración que yo realicé en el apartado disable_functions. Como no se ve todo, he querido dejarlo por aquí para que se vea algunas de las configuraciones que yo realizo por seguridad.


También, ojo, puede que a pesar de la técnicas que he comentado de seguridad por oscuridad en el Apache, puede que aún se vean versiones de PHP, y eso para un atacante en una fase de fingerprinting puede resultar valioso, ya que le puede bastar con curl -i webvictima.com | less y obtener información de ese tipo.
¿Cómo podemos solventar todo esto? Nos puede bastar con dentro de php.ini irnos al campo expose_php y dejarlo en "Off".




No lo he dicho antes, pero para que se apliquen los cambios que hemos realizado tendremos que lanzar /etc/init.d/apache2 reload para cargar la configuración.
Tenemos que tener mucho cuidado con lo comentado de seguridad por oscuridad para no mostrar mucha información y sobre todo, tener mucho cuidado con las funciones PHP que estamos permitiendo realizar, ya que os recuerdo que si miramos el Top 10 de OWASP, los ataques por inyección siguen en el número 1.


A ver, hay muchas cuestiones a tocar aquí, y eso es sobre todo porque esto ya es un tema más de programación y cada desarrollador es un mundo. Así vemos muy claramente que en un proyecto web, hay muchas cuestiones a tener en cuenta, el código, el servidor web, el servidor de base de datos, el Kernel,etc. Aquí os dejo algunos posts muy interesantes para mejorar la seguridad y optimizar PHP.

Optimizando y medidas de seguridad en MySQL

Sobre bases de datos podemos meternos a hablar y no pararíamos nunca, hay mil aspectos que tener en cuenta y mil aspectos que tocar. Por empezar por algún lado, vamos a decir que yo recomiendo utilizar el gestor InnoDB, que fuera de los mitos que se crearon con su salida, es un gestor muy recomendado.

Ahora vamos con quién va a poder acceder a la base de datos. Lo lógico es que solamente permitamos que se acceda mediante localhost, y para esto tendremos que acceder al archivo my.cnf en /etc/mysql y comprobar que la siguiente línea sea igual:

bind-address = 127.0.0.1


Después un /etc/init.d/mysql restart

//Si lo tenéis con 0.0.0.0 ya podéis rezar por cómodos :P

Otro aspecto importante es que el número de clientes que tenemos en el archivo de configuración de Apache y en el de MySQL, ya que si tuviésemos en el Apache 1024 clientes y en MySQL 500, el cuello de botella nos vendría en la Base de datos y eso dará error de rendimiento.

Otro apecto a tener en cuenta es comprobar las long_query de tus bases de datos. Esto lo vemos entrando en la base de datos y escribiendo SHOW GLOBAL VARIABLES LIKE "long_query_time";

Y una cosa que me sorprende, es que hay gente que en sus bases de datos no utiliza índices, lo que afecta a la velocidad y por ende al rendimiento. Utilizad índices.

Como he dicho, existen muchas cuestiones a tener en cuenta, además todo dependerá de vuestro caso particular, así que toca ir probando.

Seguridad por oscuridad con SSH


SSH es otro de los aspectos que tendremos que tocar, ya que una mala configuración aquí podría permitir el acceso a un atacante. Vamos a modificar el archivo /etc/ssh/sshd_config con algunas opciones.




Lo primero es añadir "DebianBanner no" para no mostrar el banner de SSH. Esto es algo muy efectivo, pero a lo mejor lo que queremos es "bloquear" a Nmap y que no muestre que tenemos SSH abierto.


En el mismo archivo de configuración de SSH, en el campo Port cambiamos el puerto, esto lo que provocará es que si un atacante escanea la red, no encontrará que el SSH esté abierto. {Por supuesto hacemos uso de /etc/init.d/ssh restart para que se guarde la configuración}


Lanzando nmap veremos que ya aparece nada referente a ssh, por lo que ya no es sólo que el atacante no sepa de primeras si está abierto o no, sino que que además estás evitando una carga alta en tu servidor si el atacante intentase un ataque de fuerza bruta, lo que te da disponibilidad de forma indirecta.


Pero supongamos que da con el SSH y su puerto que hemos utilizado e intentasen entrar como root y sacan la password. Si en el archivo de configuración tenemos deshabilitado el PermitRootLogin without-password, el atacante podrá entrar sin problema como vemos. Este campo lo que nos permite en caso de esta habilitado es que desde el usuario root, solamente se pueda acceder mediante cetificados.



En cambio, al habilitar este campo //descomentarlo en este caso vemos que ni con la password podemos entrar, por lo que será muy importante tenerlo activo, ya que se trata del usuario root. Ni que decir tiene, que si accediesen a un usuario que no sea root porque den con la contraseña, que el usuario root y ese usuario tengan una password distinta, ya que si tirasen de otro ataque de fuerza bruta, sería el segundo ataque en poco tiempo, por lo que lo podríamos detectar fácilmente.

Realizando DoS con UfoNet y ab...salimos victoriosos.

Ya sólo nos queda realizar el mismo ataque para ver si nuestro server lo aguanta con esta configuración.


Al principio tiré de UfoNet, una herramienta que me encanta. Esto fue como el calentamiento, ya después tiré de la herramienta de apache2-utils ab.


Tras tirar de ab, miré con netstat y vi las 100 peticiones recibidas. Al principio hice el mismo ataque con el mismo nivel de concurrencia y ahora lo aguantó como un campeón, así que vamos a apretar las tuercas.


Aumenté las consultas a 200, la doblé, y como he dicho, podemos lanzar apachectl fullstatus o accediendo vía web con http://miweb.com/server-status //o escribir localhost/server-status.



Aquí vemos cómo hice la captura con las primeras 50 consultas. Decir que yo lo estaba haciendo en una VM con menos de 1GB, por lo que lanzar ab y comprobar el estado del server, muchas veces es complicado porque daba fallo y se pillaba, pero esto lo tenéis que imaginar en un servidor con mayor capacidad, esto es una PoC. Con lo que os tenéis que quedar es que con 200 consultas aún aguanta, y subiendo el nivel de concurrencia a 100, aún me aguantaba; y ya digo, en una máquina normalita y a la que, en menos de 5 minutos, ejecuté ab 4-5 veces, por lo que aguantar eso tiene mucho mérito.

Finalmente os puedo decir que utilicéis herramientas para detectar rootkits como puede ser rkhunter, y que añadáis IDS, buenas políticas Iptables y un largo etc.
Hay mil opciones y mil formas distintas de hacer lo mismo, estoy seguro. Esto pretende ser una guía básica de "por dónde empezar", pero al final te va a tocar dedicarle horas delante del ordenador mirando manuales y probando, sobre todo probando, haciendo pruebas de estrés, capturando tráfico y agregar IPs sosprechosas a las políticas de iptables.
Después también tengo que decir que aplicar lo que aquí he enunciado me llevó algo más de 2 horas, pero teniendo en cuenta que tenía que tomar capturas, fui a prepararme la cena, cenaba mientras lo hacía y mi novia pidiéndo encarecidamente que descansara un poco, es decir, que en circunstancias reales y con concentración, no se debería tardar más de 1 hora.

No puedo terminar este post sin ponerme en el caso de que todo esto no haya servido y aún así nos hayan conseguido atacar. Pues bien, para esto lo que toca es:
  • Restaura las configuraciones y vuelve a empezar.
 Al fin y al cabo, solucionar el problema una vez que ha ocurrido, puede resultar más complicado, pues necesitaremos un plan de contingencia que hemos tenido que pensar antes de que ocurra el error.


Debemos de tener en cuenta que los datos del usuario no deben perderse, pero si estamos en una red social, hemos recuperado toda la base de datos, excepto 2 fotos de 2 usuarios, pues bueno, tenemos disponibilidad que es muchas veces importante. Al fin y al cabo depende del entorno en el que estemos, ya que podemos sacrificar algunos datos que podamos recuperar fácilmente para centrarnos en la disponibilidad.

En cuanto a la disponibilidad, también hay que matar mitos. Si tenemos una web normalita y se cae durante 1 hora, pues bueno, no es tan relevante como que un banco o Amazon se caiga 1 hora. Tengamos eso también en cuenta, que muchas veces parece que tenemos que ir con la escopeta cargada y cualquier memez reprocharla.

Para concluir solamente puedo decir que este camino os lo tenéis que hacer vosotros con los fallos que os vayan sucediendo en entornos totalmente distintos. Así que nos quitamos el sudor y nos ponemos en marcha.

¿Hackeamos el Mundo?

2 comentarios:

  1. I like the helpful info you provide in your articles. I will bookmark your blog and check again here frequently. I’m quite sure I will learn plenty of new stuff right here!
    Best of luck for the next!

    ResponderEliminar
    Respuestas
    1. Hi. Thank you very much for your comment. I always try to do the best and i'm trying to have articles in english too, so if you want write an article...just send it to me!!

      I hope you have a great weekend

      Eliminar

Related Posts Plugin for WordPress, Blogger...

Entrada destacada

El server me sabe a poco.

Soy un fanático del Rock y de Debian . (Creo que voy a inventar Rockbian, que suena bien y todo xD) Llevaba tiempo queriendo unir estos 2 c...