IT & Engineering
Guía de seguridad: Cómo proteger tu infraestructura de los ataques básicos
Ejecutar tu infraestructura con una configuración segura es una tarea desalentadora incluso para los profesionales de la seguridad. Esta guía proporciona consejos prácticos para ayudar al equipo de ingeniería a crear una infraestructura siguiendo las mejores prácticas de seguridad para que puedan implementar sus servicios en la Internet pública con confianza y reducir las posibilidades de sufrir vulnerabilidades. Esta guía se centra específicamente en los sistemas basados en Linux; sin embargo, las mejores prácticas se aplican a todos los sistemas informáticos.
Ejecutar tu infraestructura con una configuración segura es una tarea desalentadora incluso para los profesionales de la seguridad. Esta guía proporciona consejos prácticos para ayudar al equipo de ingeniería a crear una infraestructura siguiendo las mejores prácticas de seguridad para que puedan implementar sus servicios en la Internet pública con confianza y reducir las posibilidades de sufrir vulnerabilidades. Esta guía se centra específicamente en los sistemas basados en Linux; sin embargo, las mejores prácticas se aplican a todos los sistemas informáticos.
Parte de gestionar una infraestructura con confianza consiste en comprender contra qué y contra quién la estás protegiendo. Esta guía acabará teniendo tres versiones: Básica, Intermedia y Avanzada, y cada una se centrará en defender tu infraestructura frente a un tipo distinto de atacante.
Estás leyendo la versión Básica, cuyo objetivo es proteger frente a ataques automatizados y script kiddies que entienden las herramientas de explotación más que las técnicas de explotación. Este tipo de atacante es más oportunista que selectivo y pasa rápidamente a objetivos más fáciles. Si estás llevando a cabo un proyecto paralelo o fundando una empresa, este es el mejor lugar para empezar, ya que te ayudará a crear una base sólida sobre la que construir.
Mientras lees esta guía, ten en cuenta el tipo de atacante y los tipos de ataque de los que quieres defenderte. Las mejores prácticas que sigues y las que no dependen de lo que intentas defender y de contra quién te intentas defender.
Lista de comprobación de seguridad de la red
Esta guía sigue los siguientes principios rectores en su análisis de la seguridad del software:
- Defiende, detecta y reacciona. Esto significa aplicar unas buenas prácticas de seguridad para defender tu infraestructura, así como registrar cualquier comportamiento sospechoso y, en caso de vulnerabilidad, restaurarla a un estado seguro.
- Todo el software se puede vulnerar. Cualquier software que no sea trivial tiene fallos que permiten a un atacante con la motivación suficiente aprovecharse de él.
- La simplicidad es seguridad. Los sistemas demasiado complejos resultan más difíciles de procesar para el equipo de desarrollo y más fáciles de vulnerar para un atacante. Los sistemas más sencillos que se pueden procesar suelen ser más seguros. No implementes una solución de seguridad que no comprendes.
- La oscuridad no es seguridad. Confía en la seguridad de los protocolos que utilizas para defender tu infraestructura y no en puertos oscuros y en otros trucos para intentar ocultar protocolos inseguros.
- Considera hostil toda entrada del usuario. Considera hostiles todas las entradas aceptadas de los usuarios y verifica de manera estricta lo que aceptas.
- Principio del mínimo privilegio. Proporciona el privilegio mínimo necesario para que se lleve a cabo una operación. Si se vulnera un proceso o sistema, querrás evitar que el atacante obtenga más acceso del mínimo requerido.
Vulnerabilidades de software
Cómo protegerse frente a las vulnerabilidades de software
La aplicación estricta de las actualizaciones de seguridad de un software que tú no has programado puede parecer una mala forma de proteger tu infraestructura y quizá hasta inútil. Sin embargo, es una de las mejores inversiones de tiempo que puedes hacer desde una perspectiva de seguridad. A continuación, te mostramos dos ejemplos de problemas de seguridad recientes de los que los atacantes sin experiencia que utilizan herramientas automatizadas se pueden aprovechar si no has instalado en tus servidores los parches de seguridad más recientes:
- Heartbleed: permite que el atacante robe tus certificados privados y descifre tu tráfico cifrado
- Shellshock: permite que el atacante ejecute de forma remota código arbitrario en tus servidores
Ya solo con estos dos problemas, un atacante lograría hacerse con el control total de toda tu infraestructura. Afortunadamente, solucionar estos errores no es difícil.
Cómo reducir el daño de las vulnerabilidades del software
Aplica de manera constante las actualizaciones de seguridad que proporciona el proveedor de tu sistema operativo. La mayoría de proveedores cuentan con un método automatizado. Por ejemplo, para los sistemas basados en Debian, puedes utilizar Unattended Upgrades, y para los sistemas basados en Red Hat, puedes usar AutoUpdates.
La aplicación automatizada de parches es genial; sin embargo, tiene un posible inconveniente (para tu empresa) si no pruebas el software antes de aplicar los parches en los servidores de producción: las cosas se pueden romper de manera imprevista. Por mucho que las personas encargadas del mantenimiento de los paquetes intenten asegurarse de que las actualizaciones de seguridad no contienen cambios importantes, no pueden probar todas las combinaciones que pueden estar ejecutándose en algún lugar antes del lanzamiento. Por ese motivo, es importante tener un entorno de pruebas con sistema de integración continua/implementación continua (CI/CD) o comprobar manualmente las actualizaciones de seguridad antes de implementarlas en los servidores de producción.
Sin embargo, no basta solo con aplicar estas actualizaciones de seguridad. Si el problema se encuentra en una biblioteca compartida, estarás utilizando la versión antigua de dicha biblioteca y seguirás siendo vulnerable a que la exploten hasta que reinicies el proceso que está vinculado a ella. Para comprobar si tienes algún binario que se deba reiniciar, puedes usar checkrestart para los sistemas basados en Debian y needs-restarting para los sistemas basados en Red Hat.
Resumen
- SÍ: aplica parches en tus servidores frente a las últimas vulnerabilidades de seguridad.
- SÍ: usa las actualizaciones automáticas del proveedor de tu SO siempre que puedas.
- SÍ: reinicia cualquier servicio que dependa de bibliotecas compartidas que se hayan actualizado.
- NO: implementes actualizaciones en un servidor sin realizar pruebas.
Refuerzo de la red
¿Qué es el refuerzo de la red?
Reforzar tu aplicación usando las funciones a nivel de SO es un enfoque eficaz para limitar el alcance del daño que los atacantes pueden infligir una vez hayan explotado una vulnerabilidad de tu aplicación. Esta sección se centra en utilizar las funciones de control de acceso de Unix tradicionales con las que la mayoría de usuarios se han familiarizado para restringir tu aplicación al conjunto de acceso mínimo que necesita para funcionar. Las funciones son los permisos de los archivos, el identificador de usuario (UID) y el acceso root.
El objetivo de esta sección no es reforzar tu aplicación de tal forma que ningún atacante la pueda poner en riesgo. Ese es un objetivo prácticamente inalcanzable. El objetivo es limitar lo que el atacante puede hacer una vez se haya puesto en riesgo tu aplicación. Una vez que el atacante haya explotado tu aplicación, podrá realizar acciones como si fuera tu aplicación, y es posible que hasta eleve sus privilegios al nivel root, lo que le permitiría tener acceso total y completo a tu sistema operativo. En su lugar, el objetivo consiste en restringir las acciones que puede realizar tu aplicación al limitado conjunto que necesita para funcionar, lo que a su vez restringe al atacante.
Cómo reducir el daño al reforzar la red
Deberás restringir tu aplicación de tal modo que, incluso si el atacante explota tu proceso y logra ejecutar el código como si fuera esa cuenta de usuario, el usuario tenga derechos de acceso limitados al sistema de archivos. El mismo concepto se aplica al proceso bajo el que se está ejecutando la cuenta: restringir el tiempo de la CPU, la memoria y el recuento del descriptor de archivos para mitigar los ataques de tipo DOS, en los que el atacante agota tus recursos. El objetivo es obligar al atacante a utilizar un ataque de escalado de privilegios (explotar otra parte de tu sistema operativo para que sus privilegios sean superiores a los de la aplicación en ejecución) para hacer cualquier cosa de peso en tu sistema.
Para restringir la cuenta en la que se ejecuta tu aplicación, utiliza las directrices siguientes:
- Nunca ejecutes tu aplicación como root o como un usuario con funciones sudo. Si se explota tu aplicación, el atacante puede lograr obtener privilegios root.
- Si tienes varias aplicaciones, y cada una accede a datos confidenciales distintos, considera la posibilidad de ejecutar cada una con su propia cuenta y, a continuación, utilizar los privilegios del sistema de archivos para aislar el acceso a los datos confidenciales entre sí. Esto significa que los datos confidenciales de la aplicación nunca deben tener configurados otros permisos que permitan su lectura y escritura a cualquiera. Por ejemplo, nunca configures los permisos con un valor como
0777; en su lugar, utiliza un valor como0660. - Asegúrate de que tanto el usuario como el grupo de la aplicación tengan privilegios limitados. Esto significa crear un nuevo usuario y grupo limitados para la cuenta y no darle un shell al usuario. Imagina que tienes una aplicación llamada
foo. Crea un usuario llamadofooappy haz que su directorio principal sea/var/appdata/fooapp:sudo useradd -r -s /bin/false --home /var/appdata/fooapp fooapp sudo mkdir /var/appdata/fooapp sudo chown fooapp:fooapp /var/appdata/fooapp - Demoniza tu aplicación para que se inicie automáticamente como un usuario concreto. Hay dos enfoques generales para resolver este problema. El primero consiste en utilizar las facilidades del sistema operativo (como los scripts de inicio de System V (Red Hat / Debian) o systemd (Red Hat/ Debian) para iniciar y detener tu aplicación y luego utilizar una herramienta de monitorización de procesos (como monit) para reiniciar tu aplicación si falla. El otro enfoque consiste en utilizar un sistema de control de procesos (como supervisord, skarnet s6, daemontools) que inicie tu aplicación como proceso secundario y también la reinicie si falla. Ambos enfoques son completamente válidos y utilizar uno u otro dependerá de cuál se adapte mejor a tu flujo de trabajo.
Para restringir el proceso que ejecuta tu aplicación, sigue estas directrices:
- Asigna límites por proceso utilizando el archivo
/etc/security/limits.conf. Por ejemplo, si deseas limitar el número de descriptores de archivo abiertos a 10 y limitar la memoria a 1 GB, añade las siguientes líneas al archivo/etc/security/limits.conf:
fooapp hard nofile 10 # límite de 10 descriptores de archivo abiertos fooapp hard as 1000000 # límite de 1 GB
- No vincules tu aplicación a un puerto bajo. Normalmente debes ejecutar tu aplicación con privilegios administrativos para hacer esto. En su lugar, vincúlala a un número de puerto alto y utiliza un proxy inverso para desviar las peticiones a tu aplicación. A continuación, utiliza las capacidades de Linux para permitir que tu proxy inverso se vincule a un puerto bajo sin ningún otro privilegio. Por ejemplo, si tienes un proxy inverso en
/opt/rproxy, puedes configurar sus capacidades de la siguiente manera:
setcap 'cap_net_bind_service=+ep' /opt/rproxy
- Por último, considera utilizar
chroot, pero ten en cuenta que requiere un cierto trabajo de mantenimiento.chrootte permite limitar el alcance de lo que puede ver un proceso en el sistema de archivos; en concreto, cambia tu directorio raíz a un directorio de tu elección. Por ejemplo, si defines/var/chrootcomo tu nuevo directorio raíz, los procesos verán los archivos bajo/var/chrootcomo/. Aunque esto es más seguro, significa que las bibliotecas compartidas que pueda utilizar tu proceso deben copiarse y residir en/var/chroot, lo que a su vez implica que, cada vez que apliques actualizaciones de seguridad, también deberás volver a copiar cualquier biblioteca compartida actualizada. Puedes evitar este mantenimiento con enlaces físicos, pero entonces estarás ofreciendo una ruta exterior que un atacante puede explotar. Otros enfoques (basados en cgroups) que puedes adoptar para obtener beneficios similares se analizarán en la versión intermedia de esta guía.
Resumen
- SÍ: crea una cuenta restringida para ejecutar tu aplicación, lo que significa sin shell y con acceso limitado al sistema de archivos.
- SÍ: vincula tu aplicación a un puerto alto, lo que te permitirá ejecutarla como usuario sin privilegios.
- SÍ: utiliza capacidades en lugar del usuario raíz siempre que puedas.
- NO: utilices chroot a menos que estés preparado para asumir el trabajo de mantenimiento.
Seguridad del firewall de red
Cómo revisar las reglas del firewall
Unas reglas de firewall sólidas te permiten definir qué comunicaciones entrantes y salientes se permiten desde tus servidores. Empezar con una política de denegación predeterminada y permitir solo tráfico específico de entrada y salida te obliga a pensar en el conjunto mínimo de servicios que deseas exponer, lo que a su vez puede reducir el riesgo de sufrir ataques. Un proceso erróneo no puede exponer toda tu infraestructura al público general a menos que lo permitas específicamente.
Esta sección se centra en las reglas del firewall para el tráfico entrante y en los ajustes de la pila TCP/IP. Aunque las reglas del firewall para el tráfico saliente son muy eficaces a la hora de limitar hasta dónde puede llegar un atacante una vez que ha entrado en tu infraestructura, la próxima versión de esta guía se centrará en ellas.
Mitigación
Primeras reglas de firewall. Al crear un script para las reglas del firewall, utiliza los siguientes principios básicos.
- Borra las reglas de firewall existentes. Al desarrollar las reglas del firewall, necesitas tener una idea coherente de lo que estás bloqueando y permitiendo. Descartar todas las reglas existentes y empezar desde cero logra este objetivo.
- Configura la regla predeterminada para el tráfico entrante como DROP. Esto sigue el principio de privilegios mínimos. Tras definir la política predeterminada como DROP, podrás ir abriendo tu red poco a poco.
- Permite el libre acceso a la interfaz de bucle invertido. A diferencia de las interfaces externas, vincular tu proceso a localhost suele ser bueno para la seguridad y, por lo tanto, restringir el acceso a la interfaz de bucle invertido causa más daño que beneficio. Esto te deja expuesto a un ataque de un usuario local, pero es un riesgo que debes sopesar tú mismo.
- No finalices las conexiones establecidas. Debes evitar finalizar tu propia conexión SSH a un servidor y asegurarte de que cualquier petición en curso pueda terminar antes de cerrarse.
- No restrinjas todo el tráfico del Protocolo de mensajes de control de Internet (ICMP). Permitir el protocolo ICMP es fundamental para que Internet funcione; los enrutadores y los hosts lo utilizan para comunicar información crítica como la disponibilidad de los servicios, el tamaño de los paquetes y la existencia del host. Los tipos 3 y 4 (Destination Unreachable y Source Quench) son críticos, y restringirlos causará más daño que beneficio en el futuro. Si te preocupa que un atacante pueda trazar un mapa de tu red, un término medio razonable es limitar primero la velocidad de todo el tráfico ICMP y, a continuación, permitir un subconjunto limitado de tráfico ICMP en tus hosts de borde, al tiempo que permites un acceso sin restricciones para la comunicación interna entre hosts.
- Aplica las comprobaciones de seguridad básicas. Cierto tráfico entrante no tiene un propósito legítimo; restringe ese tráfico. Si recibes ataques frecuentes de un tipo particular de tráfico, podría resultarte útil transformarlo en su propia cadena en caso de que te encuentres añadiendo normas con frecuencia a esta sección.
- A menos que utilices IPv6 y tengas un plan para crear reglas de firewall para el tráfico IPv6, restringe todo el tráfico IPv6 entrante.
A continuación, se muestra un script comentado que cumple todos estos objetivos:
A continuación, se muestra un pequeño script para el tráfico IPv6:
Estas reglas se están ejecutando ahora en la memoria y debes asegurarte de que se carguen la próxima vez que se reinicie tu sistema operativo. Para los sistemas basados en Debian, eso significa añadir tus reglas de firewall a /etc/network/ip-pre-up.d/ o bien añadir un comando pre-up a /etc/network/interfaces. Para los sistemas Red Hat, esto suele hacerse utilizando /sbin/service iptables (comando save).
Además, se recomienda el siguiente refuerzo/ajuste de la pila TCP/IP:
- Si utilizas reglas de firewall con estado, como en el ejemplo anterior, asegúrate de aumentar el número máximo de conexiones de las que puedes hacer seguimiento. De lo contrario, un atacante podría utilizar un ataque distribuido de denegación de servicio (DDoS) contra ti.
- Utiliza cookies SYN para evitar los ataques DoS de inundación SYN. Thomas Pornin ofrece una excelente explicación sobre qué son los ataques de inundación SYN y cómo las cookies SYN mitigan este tipo de ataques.
- Registra todos los paquetes marcianos ya que cualquier paquete que provenga de una dirección de origen o destino no enrutable será malicioso con toda probabilidad.
Puedes probar todos los ajustes anteriores con el siguiente script:
Para mantener estos ajustes tras un reinicio, actualiza /etc/sysctl.conf:
Resumen
- SÍ: deniega el tráfico de forma predeterminada. Permite de forma explícita solo el tráfico que sepas que debe atravesar tu red.
- NO: restrinjas el protocolo ICMP de forma unilateral.
- SÍ: permite el libre acceso a la interfaz de bucle invertido.
- SÍ: fuerza algunas comprobaciones de seguridad básicas.
- SÍ: asegúrate de que tus reglas se carguen al reiniciar.
- SÍ: ajusta tu pila TCP/IP para aumentar el número de conexiones rastreadas y protegidas contra inundaciones SYN.
Inicio de sesión remoto
Descripción
En cuanto al inicio de sesión remoto, debes asegurarte no solo de que la comunicación con tus servidores esté cifrada, sino también de que solo los usuarios autorizados tengan acceso a tus servidores. Estos son los objetivos habituales a la hora de proteger el inicio de sesión remoto:
- Ofrece acceso limitado a los usuarios para que, si una cuenta se ve comprometida, no comprometa toda tu infraestructura.
- Una criptografía fuerte garantiza que nadie pueda espiar o leer tus comunicaciones.
- Los atacantes no pueden usar técnicas de fuerza bruta para iniciar sesión en tus servidores.
- Incluso si tu clave se ve comprometida, un atacante no podrá obtener acceso a tu infraestructura.
- Un atacante que utilice técnicas de fuerza bruta no podrá agotar los recursos del servidor.
- Solo los usuarios autorizados tienen acceso a tus servidores.
- No existe el inicio de sesión para cuentas administrativas de propósito general. Todas las acciones administrativas se realizan mediante algún tipo de escalado de privilegios (
sudo) para registrar las acciones llevadas a cabo.
No alcanzar cualquiera de estos objetivos puede suponer un riesgo para la seguridad. Una criptografía débil (o inexistente) puede permitir que un atacante vea tus comunicaciones. Una autenticación débil puede permitir a usuarios no autorizados acceder a tus sistemas.
Por suerte, Secure Shell (SSH) mitiga la mayoría de estos riesgos, y con unos pocos ajustes en tus sistemas, se pueden mitigar todos.
Mitigación
Para empezar, genera tu clave SSH correctamente; asegúrate de usar un tamaño de clave lo suficientemente grande y de que tu clave esté protegida por contraseña. Puedes hacerlo usando ssh-keygen:
ssh-keygen -t rsa -b 4096 -C foo@example.com
A continuación, cuando se te pida, introduce una frase de contraseña. Una frase de contraseña garantiza que, incluso si alguien roba tu clave, no podrá utilizarla sin conocer también la frase de contraseña.
OpenSSH tiene una configuración predeterminada razonable que es bastante segura. Sin embargo, algunas distribuciones pueden debilitar estos valores predeterminados para hacer que OpenSSH interopere con servidores heredados. La siguiente configuración simplemente garantiza que tu versión de OpenSSH aplique esos valores predeterminados razonables. Para obtener información más detallada sobre la configuración de OpenSSH, consulta la Guía de configuración de Mozilla para OpenSSH y la Protección de SSH página para CentOS. Ambos son recursos excelentes y nos basaremos en esas configuraciones en futuras versiones de esta guía.
En el servidor, asegúrate de tener las siguientes líneas en el archivo /etc/ssh/sshd_config :
Esta configuración logra los siguientes objetivos:
- El Protocolo 2 garantiza que estás utilizando una versión segura del protocolo SSH. La versión 1 del protocolo tiene bastantes problemas y se considera defectuosa.
PasswordAuthentication noyPubkeyAuthentication yeste obligan a utilizar criptografía de clave pública, y no contraseñas, para autenticarte en tus servidores. Aunque puedes tener una contraseña segura, si tienes una contraseña de 2048 bits generada de forma aleatoria y codificada en ASCII, más contraseñas son malas y las longitudes de contraseña que se usan habitualmente tienen un espacio de búsqueda mucho menor que el de una clave grande.PermitRootLogin nodesactiva la posibilidad de iniciar sesión de forma remota como usuario raíz. Aunque este no es un problema directamente explotable, desactivar el inicio de sesión remoto te ayuda a mantener buenos registros de auditoría para comprender qué ocurre en tus servidores. La cuenta raíz actúa como una cuenta administrativa compartida, lo que limita tu capacidad para auditar qué usuario está realizando cada acción con privilegios. Si obligas a todos los usuarios a pasar por sus propias cuentas, obtendrás un rastro auditable de qué usuario ha realizado cada acción. En una sección posterior se ofrecen detalles sobre cómo configurar el registro de auditoría.LogLevel VERBOSEregistra el usuario y la huella digital de la clave que intentó autenticarse. De nuevo, este ajuste no mitiga directamente una vulnerabilidad, pero es bueno para la auditoría.
En el cliente, asegúrate de tener las siguientes líneas en el archivo /etc/ssh/ssh_config :
Esta configuración logra los siguientes objetivos:
- El Protocolo 2 garantiza que estás utilizando una versión segura del protocolo SSH. La versión 1 del protocolo tiene bastantes problemas y se considera defectuosa.
HashKnownHosts yesgenera un hash de los nombres de host y las direcciones en tu archivo~/.ssh/known_hosts. Incluso si un atacante roba tu archivo de hosts conocidos, no podrá enumerar sin más los hosts a los que te conectas con tu clave.StrictHostKeyChecking askcomprueba la clave que se te presenta frente a la de tu archivo~/.ssh/known_hostsy, si ha cambiado (o si es la primera vez que visitas ese host), te pregunta si aceptas esa clave. Esto ayuda a mitigar los ataques de hombre en el medio.
Por último, da a los usuarios un acceso limitado a tu infraestructura. Por ejemplo, no todos los usuarios necesitan acceder a tus servidores de copia de seguridad; solo da acceso a los usuarios que realmente sepan cómo restaurar las copias. Esto garantiza que, incluso si se ve comprometida una cuenta de usuario sin capacidad para gestionar copias de seguridad, la integridad de tus copias de seguridad no estará en peligro.
Para lograr esto, dos de los enfoques más comunes son:
- Cuentas de usuario locales. En este enfoque, creas cuentas Unix locales para tus usuarios y solo creas cuentas en los servidores a los que necesitan acceder. Puedes utilizar los comandos
newusersyuserdelpara lograrlo y automatizar/orquestar este proceso utilizando herramientas de gestión de configuración como Chef o Ansible. - Servicio de autenticación centralizado como LDAP. Con este enfoque, los servidores a los que cada usuario tiene acceso se definen y almacenan en la configuración del servidor LDAP.
Resumen
- SÍ: protege tu clave con una frase de contraseña.
- NO: asumas que tu distribución tiene valores predeterminados aceptables; define de forma estricta lo que es importante para tu infraestructura.
- SÍ: utiliza criptografía de clave pública para la autenticación en lugar de autenticación basada en contraseñas.
- NO: proporciones a todos los usuarios un acceso sin restricciones, limita el acceso solo a las partes necesarias de tu infraestructura.
Límites de confianza
Descripción
Los límites de confianza son un punto habitual en el que se producen vulnerabilidades de seguridad. El límite entre el mundo exterior y tu infraestructura interna es sagrado y debes hacer todo lo posible por defenderlo y asegurarte de que solo los usuarios autorizados puedan atravesarlo.
Deben preocuparte dos límites de confianza principales. El primero es el límite entre el Internet público y el punto de conexión de tu API; este es el límite que tus clientes cruzarán cada día al usar tu servicio. El segundo es un punto de acceso para que tu equipo de desarrollo y los administradores del sistema puedan desplegar y dar servicio a tu aplicación.
En cuanto al límite de confianza de la API que cruzará tu clientela, debes considerar cualquier entrada del usuario como hostil y asumir que cada petición realizada es, en realidad, un intento de explotar tu infraestructura. Cuando piensas en las peticiones de los usuarios de esa manera, resulta evidente que necesitas minimizar la superficie de ataque que proporcionas y aislar el daño que pueda ocurrir cuando, en un momento dado, un usuario logre explotar tu servicio.
En el caso del límite de confianza que cruzas para dar servicio a tus aplicaciones, lo ideal es aislar todos tus servicios para que no queden expuestos al Internet público y, a continuación, obligar a quienes accedan a ellos desde Internet a cruzar por un punto de acceso bien vigilado que puedas defender (llamémoslo host bastión). Puedes concentrar todos tus recursos en ese único punto de acceso y preocuparte menos por cómo se comunican tus servicios entre sí cuando se encuentran dentro de ese límite de confianza.
Mitigación
Para mitigar estos problemas con los límites de confianza, necesitas imaginar los distintos cuadros en los que puedes ubicar el Internet público y tu infraestructura (consulta el siguiente diagrama). Una vez que lo tengas, puedes empezar a pensar cómo puedes defender tu infraestructura.
El primer cuadro grande es el Internet público. No debes confiar nunca en nadie ni en nada en el Internet público. De hecho, debes considerar a todos los actores del Internet público como hostiles, incluso cuando se trate de tu propia plantilla conectándose por SSH a tus servidores.
El segundo cuadro grande es tu infraestructura interna. Estos son tus hosts de confianza. Los servicios que se ejecutan en estos servidores deben escuchar solo en interfaces de red privadas si es posible y no estar expuestos de forma directa al Internet público.
Los dos cuadros que abarcan ambos son tu host de salto y los hosts de tu API. Estos hosts deben tener acceso tanto al Internet público como a tu infraestructura interna. Puesto que están expuestos de forma directa al Internet público, deben estar reforzados y ejecutar el conjunto mínimo de servicios necesarios para cumplir sus tareas.
Refuerzo del punto de conexión de la API
Aunque no podemos esperar que ningún servicio esté libre de errores, sí que podemos limitar hasta qué punto un atacante podrá explotar tu infraestructura en caso de vulnerar tu servicio. Por eso te recomendamos aislar los servicios que acepten peticiones entrantes y ejecutarlos en sus propios servidores dedicados.
Puedes lograr esto dividiendo las peticiones entrantes en dos partes: equilibrio de carga y terminación TLS (Seguridad de la capa de transporte) de las peticiones entrantes, y el propio manejo de la petición por parte del servicio. Ambas partes deberían ser, como mínimo, procesos propios, o bien ejecutarse en servidores distintos, de manera que el equilibrio de carga y la terminación TLS se sitúen en el límite entre Confianza / Sin confianza. Esta sección se centrará en el equilibrio de carga y la terminación (el refuerzo de las aplicaciones ya se ha tratado en una sección anterior).
Al separar el equilibrio de carga y la terminación TLS de tu aplicación, limitas la posibilidad de que un error en tu equilibrador de carga o software TLS acabe en la vulneración de toda tu aplicación, la cual normalmente tendrá información confidencial cargada en la memoria. También te proporciona un único punto de mantenimiento (y de error) que puedes parchear cuando se descubre una vulnerabilidad y necesitas actualizar tu biblioteca TLS, algo que se está convirtiendo en una tarea cada vez más común.
Por ejemplo, supongamos que un atacante dispone de un error de ejecución remota de código (RCE) como GHOST o un error de lectura de memoria arbitraria (como Heartbleed) en tu servidor HTTP o software TLS. Si tu servidor HTTP, la terminación TLS y la lógica de la aplicación se encuentran en el mismo proceso, un error en cualquiera de ellos proporciona al atacante acceso a información confidencial dentro del resto de partes. Por ejemplo, un error en OpenSSL puede dar a un atacante acceso a claves confidenciales que tu aplicación haya cargado en la memoria. Por el contrario, un fallo en tu aplicación puede dar a un atacante la posibilidad de acceder a tus certificados SSL. Sin embargo, si separas estas partes, en caso de explotarse una de ellas, la otra se mantendrá a salvo, y solo perderás algunos datos confidenciales.
Para el equilibrio de carga, las opciones más habituales son NGINX, HAProxy, y Apache. La terminación TLS suele realizarse con OpenSSL; sin embargo, existen alternativas como LibreSSL y Mozilla NSS . Otra alternativa es utilizar algo parecido a vulcand, que actúa como equilibrador de carga y utiliza la biblioteca Go TLS para la terminación TLS.
Refuerzo del punto de conexión del servicio (y de todo lo demás)
Puedes reforzar el punto de conexión de tu servicio limitando el acceso a tus servidores desde el Internet público y obligando a que toda la autenticación pase por un host de salto. Esta restricción suele lograrse sin exponer tu infraestructura directamente al Internet público; en su lugar, se construye una especie de red interna a la que solo se puede acceder a través del host bastión.
Hay muchas formas de crear una red interna, y tu enfoque dependerá, en gran medida, de cómo configure tu infraestructura tu proveedor de servicios y de tus preferencias.
Por ejemplo, supongamos que alojas tus servidores en Amazon Web Services (AWS). Entonces puedes empezar con una Virtual Private Cloud (VPC) con una única subred pública. Tus servidores estarán aislados del resto de servidores de AWS y residirán en su propio bloque CIDR 10.0.0.0/16 . Sin embargo, seguirán teniendo acceso a Internet sin restricciones. Para restringir el acceso desde Internet, crea Grupos de seguridadque aíslen tanto los puertos que están abiertos como los servidores que pueden acceder a esos puertos. Por ejemplo, configurarías tus hosts de trabajo para aceptar conexiones en los puertos 22 y 80, pero únicamente desde tu host de salto y equilibrador de carga, respectivamente. Sin embargo, tu servidor de salto aceptaría conexiones en el puerto 22 desde cualquier servidor del Internet público.
Si tu proveedor de servicios no ofrece estas herramientas, puedes lograr lo mismo siempre que ofrezca asistencia para algún tipo de red privada, ya sea compartida o dedicada, que te permita aislar el tráfico público del privado. Esta función suele ofrecerla la mayoría de los proveedores: como hemos mencionado antes, Amazon la llama VPC, Rackspace la denomina ServiceNety Digital Ocean la llama Private Networking. Todos ofrecen básicamente la misma capacidad: al crear tu servidor virtual, puedes vincularlo a la interfaz pública, a la privada o a ambas. Si tu proveedor de servicios no cuenta con esta función durante el tiempo de compilación, puedes activar y desactivar estas interfaces tú mismo en el archivo /etc/network/interfaces de un sistema basado en Debian y en el archivo /etc/sysconfig/network-scripts/ifcfg* de un sistema basado en Red Hat.
Una vez que tengas servidores con interfaces públicas y privadas, utiliza iptables para restringir el tráfico entrante a las interfaces de acceso público de los servidores que actúen como hosts de salto o ejecuten la API de acceso público. Los servidores que gestionan todos los servicios internos, como la aplicación y el servidor de la base de datos, rechazan cualquier tráfico entrante a las interfaces públicas y restringen el tráfico entrante a las interfaces privadas para que solo provenga del grupo de servidores de confianza.
Una vez hecho esto, la única forma que tiene un atacante de vulnerar tu infraestructura desde el Internet público es entrar desde tu host bastión reforzado o explotar tu API de algún modo.
Por último, para acceder a estos servidores, no utilices ssh-agent; en su lugar, utiliza ProxyCommand. Aunque ssh-agent tiene su utilidad, no resulta adecuado para este caso de uso en concreto. Si lo hicieras, cualquiera con un exploit local de escalado de privilegios para tu servidor bastión podría acceder a cualquier servidor de tu infraestructura suplantando la identidad de cualquier usuario cuyas claves estuvieran actualmente cargadas en memoria por ssh-agent. En cambio, con ProxyCommand, tus claves no se quedarán en la memoria para que alguien pueda robarlas y tu clave privada vivirá exclusivamente en tu estación de trabajo local; solo tu clave pública se copiará a cada servidor al que necesites acceder.
Para usar ProxyCommand, copia tu clave pública a ~/.ssh/authorized_hosts en todos los servidores a los que necesites acceder. A continuación, actualiza el archivo ~/.ssh/config de tu estación de trabajo con la siguiente información:
Esta configuración te permite acceder a server1.example.com y server2.example.com desde workstation.example.com a través de SSH en sus interfaces privadas “saltando” a través de jump.example.com, que tiene acceso tanto a las interfaces públicas como a las privadas. Para conectarte, solo tienes que escribir ssh server1.example.com o ssh server2.example.com.
Resumen
- SÍ: utiliza un equilibrador de carga para separar el servidor HTTP de tu aplicación del servidor HTTP de cara al público.
- SÍ: termina el TLS en el equilibrador de carga.
- SÍ: utiliza un host de salto reforzado para controlar el acceso a tu infraestructura.
- NO: utilices un agente SSH, a ser posible. Deja todas tus claves en peligro de exposición si alguien encuentra un exploit local de escalado de privilegios.
- SÍ: utiliza las interfaces públicas y privadas de tu proveedor de servicios para aislar tus servicios internos del Internet público.
Monitorización y registro
Descripción
Todas y cada una de las medidas de seguridad pueden ser burladas y, de hecho, lo serán en algún momento. Dado que no existe ninguna medida práctica que pueda proporcionar garantías de seguridad férreas, es importante contar con instalaciones de supervisión y registro sólidas que te ayuden a entender dónde y cómo se vieron comprometidos tus sistemas. Cuanto mejor comprendas qué se está ejecutando en tus sistemas y cómo lo hace, más capacidad tendrás para detectar comportamientos anómalos. De la misma manera que un banco instala cámaras de seguridad aunque ya cuenta con cajas fuertes reforzadas, disponer de buenas herramientas de monitorización resulta clave para atrapar a los intrusos que consigan sortear tus medidas de seguridad.
La monitorización y el registro adoptan dos formas. La primera es la monitorización en vivo, que te permite ver qué ocurre en tu sistema en cualquier momento. Esto engloba todo, desde los sockets de red que están abiertos hasta los procesos que se están ejecutando en la actualidad. La segunda son los datos de registro de las acciones que ya se han llevado a cabo. Esto abarca todo, desde el registro lógico de la aplicación hasta los registros del sistema.
En esta sección, veremos cómo analizar los registros del sistema en los propios servidores individuales. En la versión intermedia de esta guía, hablaremos sobre la suma y las alertas de registros.
Mitigación
Las siguientes herramientas vienen integradas en la mayoría de los sistemas operativos basados en UNIX. Resultan muy útiles cuando sospechas que se está produciendo un incidente de seguridad, pero también es crucial emplearlas de antemano para poder comprender cuál es su resultado normal.
Monitorización en vivo
A continuación, se indican algunos comandos y el resultado esperado en condiciones normales de funcionamiento. Estos ejemplos ilustran el aspecto que debería tener el resultado en tu
who – Te muestra quién ha iniciado sesión en este momento.
last -a – Te muestra una lista de los últimos usuarios que han iniciado sesión. Imprime el nombre de usuario, la hora de inicio de sesión y las direcciones IP desde las que se ha accedido.
netstat -plntu – Muestra los nombres de los procesos y los puertos en los que escuchan conexiones.
netstat -ap – Muestra una transmisión en vivo de todas las conexiones, incluidas las conexiones salientes establecidas.
find / -mtime -1 -ls | head -n 20 – Enumera los 20 archivos principales modificados en las últimas 24 horas.
faillog -a para ver un resumen de los errores de inicio de sesión. Esto también resulta útil para limitar el número máximo de intentos fallidos de inicio de sesión por usuario.
tcpdump -i eth1 -s 0 -A tcp port http – Vuelca todo el tráfico HTTP en la interfaz eth1. Esto es útil si has encontrado algo sospechoso utilizando netstat y deseas indagar más al respecto. Esta guía no puede ofrecerte todos los detalles sobre tcpdump, pero existen múltiples recursos en Internet que te ayudarán a entender el funcionamiento de tcpdump.
Monitorización de registros
A continuación te indicamos algunas reglas generales sobre cómo tratar el registro de aplicaciones e indicadores hacia los registros importantes del sistema.
Registros de aplicación generales
Agrupa los registros de tu aplicación en una ubicación central, ya sea un único archivo de registro o un directorio. El enfoque más común para ello es utilizar syslog para esta capacidad. Utilizar syslog facilitará en el futuro el envío de los registros a un servidor de registros central.
Mantén tus registros durante todo el tiempo que te permita el espacio en el disco. Conservar registros en el disco hasta un total de 90 días no es ninguna locura si cuentas con el espacio para ello.
Registros del sistema
Al igual que con la monitorización en vivo, te recomendamos vigilar de forma periódica los siguientes archivos de registro del sistema a fin de desarrollar una buena línea de base de resultados esperados. Contar con líneas de base facilita en gran medida la detección de comportamientos sospechosos en el futuro. Esta es una lista parcial de algunos registros del sistema interesantes que debes vigilar:
/var/log/auth.log– Registros de autenticación del sistema./var/log/syslog– Si no envías los registros a una instalación concreta de syslog, se ubicarán aquí./var/log/messages– Mensajes de registro generales del sistema.~/.bash_history– Lista de comandos Bash que ha ejecutado el usuario. Los atacantes más sofisticados pueden borrar o manipular fácilmente este registro./var/log/utmpy/var/log/wtmp– Estos registros contienen los usuarios actuales que han iniciado sesión y el historial de todos los usuarios que han iniciado sesión. Utilizalast -fpara ver estos archivos.
Resumen
- Aprende un par de comandos básicos que pueden ayudarte a averiguar qué está ocurriendo en tus servidores ahora mismo. Estos comandos incluyen
who,last,lsof,netstat,faillogyfind. - Averigua qué necesitas registrar. Los registros no resultan útiles si no capturan aquellos eventos críticos para la seguridad. Como mínimo, deberías monitorizar los siguientes archivos:
/var/log/auth.log,/var/log/syslogy/var/log/messages. - Empieza a centralizar tus registros lo antes posible. Utilizar syslog ahora en lugar de un marco de registro personalizado facilitará el envío de los registros a un servidor de registros central en el futuro.
Uso de criptografía
Descripción
La criptografía es un tema muy complejo del que se debe hablar por separado. Incluso los despistes o fallos más leves pueden comprometer por completo la seguridad de un producto. Por este motivo se repite tan a menudo el mantra de “no programes tu propia criptografía”. Dos buenas fuentes que puedes leer antes de empezar a trabajar con la criptografía son Crypto101 escrito por Laurens Van Houtven (lvh) y los retos criptográficos de Matasano.
Dicho esto, mantener tu infraestructura a salvo requiere el uso de cierta criptografía, y existen patrones comunes que pueden emplearse de forma segura. Esta sección aborda uno de esos patrones: cómo almacenar datos confidenciales en el código fuente (o en el disco).
Mitigación
Cuando almacenes credenciales, ya sea en el control de código fuente o en el disco, no lo hagas sin cifrar. Puede que creas que tus contraseñas están seguras si utilizas un repositorio privado de GitHub, pero no es recomendable que confíes en GitHub para mantener a salvo de los atacantes toda tu infraestructura. Si cifras tus credenciales, podrás mantener tu seguridad incluso si GitHub se ve comprometido.
Al buscar una herramienta o biblioteca para cifrar pequeñas cantidades de datos, ten en cuenta las siguientes recomendaciones:
- Utiliza un cifrado simétrico moderno. Dos opciones habituales son AES y Salsa20 (NaCl).
- Si tu cifrado simétrico admite distintos modos, selecciona el modo con cuidado. Por ejemplo, CBC es un buen modo de uso para AES, pero no ECB.
- Utiliza un código de autenticación de mensajes (MAC) para asegurarte de que nadie haya manipulado los datos cifrados. Las opciones HMAC-SHA-512 o Poly1305 son buenas.
- Utiliza una fuente de valores aleatorios de alta calidad, lo que normalmente significa utilizar
/dev/urandompara obtener los números aleatorios empleados en claves, salts y nonces. - Si la biblioteca o herramienta funciona con frases de contraseña, asegúrate de que utiliza un KDF para transformar la frase de contraseña en una clave.
Puedes construir tú mismo una herramienta de cifrado; sin embargo, como ya se ha mencionado, puede resultar complejo y no es recomendable. No obstante, si te empeñas en construirla, utiliza una biblioteca como NaCl o cryptography.io que, por lo menos, ejecutará la criptografía de forma correcta para ti. Sin embargo, es todavía mejor usar una “receta” que haya construido alguien para hacer esto, como lemma o Fernet que exponen una sencilla API que puedes emplear para cifrar y descifrar datos de forma segura.
Resumen
- NO: elijas al azar el modo en que estás empleando tu cifrado simétrico.
- SÍ: utiliza un cifrado simétrico autenticado con un MAC.
- SÍ: utiliza
/dev/urandompara generar material aleatorio. - SÍ: utiliza una “receta” parecida, si puedes.
Copias de seguridad
Descripción
Aunque es posible que las copias de seguridad no parezcan encontrarse en la misma categoría que el resto de temas tratados en esta guía, son igual de importantes para la seguridad de la infraestructura. Las copias de seguridad tienen dos objetivos principales: restaurar el sistema en caso de un fallo del hardware no malicioso, y restaurarlo si un atacante compromete tu infraestructura. Recuerda: en caso de que ocurra una vulneración, es mejor borrar tu servidor y crear uno nuevo que tratar de eliminar el malware, algo que puede resultar muy difícil, o casi imposible, para alguien novato. Por este motivo, en caso de vulneración, las copias de seguridad son vitales a la hora de devolver tu infraestructura a un estado de confianza.
Mitigación
Los siguientes enfoques son una buena estrategia general a seguir a la hora de trabajar con copias de seguridad:
- No dejes tus copias de seguridad desprotegidas por el simple hecho de que no parezcan de vital importancia para tu servicio. Esa es la razón por la que los atacantes atacan frecuentemente la infraestructura de copias de seguridad.
- Haz copias de seguridad con la frecuencia adecuada para las necesidades de tu empresa. Una vez al día es razonable.
- Tus servidores de copias de seguridad deben tener acceso limitado, y las cuentas que existan deben utilizar mecanismos de autenticación y autorización distintos a los empleados en el resto de tu infraestructura. Por ejemplo, tus servidores de copias de seguridad deben usar una clave SSH distinta para el inicio de sesión. Si sigues estos pasos y tu entorno principal se ve comprometido, seguirás teniendo copias de seguridad fiables desde las que restaurar.
- Si no quieres gestionar tu propia infraestructura de copias de seguridad, haz copias de seguridad en el almacén de datos de un tercero como Amazon S3. Ten en cuenta que, si vas a utilizar algún servicio de terceros, debes cifrar tus copias de seguridad antes de enviarles tus datos. Trabaja asumiendo que tu almacén de datos es de acceso público y utiliza el cifrado para proteger tu información. Si trabajas con esta mentalidad, aunque tu host se vea vulnerado, tus datos estarán a salvo.
- Si utilizas Amazon S3 o Rackspace CloudFiles, usa una receta de cifrado autenticado como lemma o Fernet. Si no quieres preocuparte por la criptografía, usa un servicio que cifre tus datos en el cliente y solo envíe blobs cifrados a su servicio, como Tarsnap.
- Haz copias de seguridad de tus repositorios de código fuente, de cualquier software de terceros que emplee tu aplicación y de tu base de datos. El ejemplo reciente de FoundationDB ilustra la importancia de hacer copias de seguridad de cualquier software que utilices. El equipo de desarrollo puede revocar las descargas de software en cualquier momento y por cualquier motivo.
- Aunque los sistemas de control de versiones distribuidas (DVCS) como Git ofrecen cierta redundancia, no sustituyen a las verdaderas copias de seguridad. No debes depender de que una rama concreta se encuentre en la estación de trabajo de una persona del equipo para garantizar la continuidad del negocio.
- Haz una copia de seguridad de tu base de datos utilizando el método que prescribe la propia base de datos.
- Restaura desde copias de seguridad con la misma frecuencia con la que ejecutas las propias copias. Las copias de seguridad no sirven de nada si no se pueden utilizar. En el mejor de los casos, puedes ejecutar algunos servicios auxiliares que no requieran tener los datos más recientes frente a tus copias de seguridad restauradas. De este modo, si algo sale mal, lo sabrás de inmediato.
- Asegúrate de que varias personas de tu equipo sepan cómo realizar restauraciones desde copias de seguridad. Tal vez seas capaz de averiguar cómo restaurar tus copias de seguridad, o tal vez no. Podría llevarte una hora o diez horas. Es mejor dedicar unas horas cada trimestre a revisar tu infraestructura de copias de seguridad junto al equipo.
Resumen
- NO: utilices para las copias de seguridad las mismas cuentas que en tu entorno principal.
- SÍ: haz copias de seguridad de los repositorios fuente, del software de terceros y de las bases de datos.
- SÍ: intenta realizar restauraciones desde copias de seguridad con la misma frecuencia con la que ejecutas el procedimiento para obtenerlas.
- SÍ: ejecuta servicios auxiliares a partir de copias de seguridad restauradas si tienes la oportunidad.
- NO: tengas un único punto de fallo, asegúrate de que varias personas de tu equipo puedan llevar a cabo restauraciones desde copias de seguridad.
- SÍ: cifra tus copias de seguridad con un cifrado autenticado. Utiliza una herramienta como lemma o Fernet, o una solución alojada como Tarsnap.