Feeds 3
Artículos recientes
Nube de tags
seguridad
mfa
dns
zerotrust
monitorizacion
kernel
bpf
sysdig
port knocking
iptables
linux
pxe
documentación
rsyslog
zeromq
correo
dovecot
cassandra
solandra
solr
systemtap
nodejs
redis
hadoop
mapreduce
firewall
ossec
psad
tcpdump
tcpflow
Categorías
Archivo
Proyectos
Documentos
Blogs
Ideas para autenticación de doble factor doméstica Sun, 19 Jun 2022
No hay duda de que la autenticación de doble factor va ganando importancia. Aunque pueda ser molesto en algunos casos, no parece haber debate si se dice que es una de esas tecnologías que están para quedarse, de una u otra manera.
Nada nuevo. Si usas un panel de control o alguna aplicación de web de alguno de los proveedores importantes, casi seguro que tendrás opciones para 2FA.
El objetivo de este post es dar algunas ideas para llevar el concepto detrás de la autenticación de doble factor a entornos más pequeños, o a aplicaciones que no tienen ningún tipo de integración de este tipo. ¿Cómo damos dos tipos de autenticación al puerto de correo saliente de un servidor casero? ¿De un servidor IMAP, SSH, o de alguna aplicación del siglo pasado?
Hablando de los ejemplos, podríamos discutir que un servidor SSH "bien trabajado", haciendo uso de todas las funcionalidades que ofrece a nivel SSL, hosts, certificados cliente, etc, da un nivel suficiente de seguridad. De la misma manera, podríamos decir que un Dovecot (hablando de servidores IMAP) integrado con Weakforced y una buena política de seguridad (geolocalización, intentos de login fallidos, ...), también sube la seguridad de la aplicación a un nivel aceptable. Si, además de estas medidas, planteamos el uso de software tipo fail2ban para crear reglas firewall en base a lo que se ve en los logs, es razonable darnos por satisfechos en, recuerdo, entornos pequeños.
Con esto terminaríamos el post, de no ser porque creo que estas medidas tienen dos aspectos que podrían mejorarse:
- El puerto del servicio está abierto, aunque fail2ban, o la gestión de accesos en general, podría cerrárselo a una IP ante el mínimo error.
- Las medidas de seguridad adicionales se aplican sobre el propio servicio. No hay nada de malo en esto pero, tal y como lo veo yo, que un usuario IMAP use, además de su cliente de correo, un formulario web para darse acceso, es una buena mejora.
En realidad, ninguna de estas ideas es nueva. El port-knocking existe hace mucho tiempo, y hay implementaciones como fwknop que han funcionado perfectamente, aunque, en este caso concreto, hace tiempo que no tiene actualizaciones. Novedad o no, ya sabéis lo que pasa en cuanto una aplicación es visible en Internet, así que creo que es importante intentar que el firewall tenga cerrado el acceso hasta que una tercera aplicación lo abra.
Por supuesto, ninguna medida "extra" debería deshabilitar el control de acceso propio de cualquier aplicación.
Abrir firewall bajo demanda y por tiempo limitado
Si me lo preguntáis a mí, a falta de cosas más elaboradas, algo tan sencillo como conseguir que un puerto esté cerrado hasta que accedamos a una URL web concreta es una medida estupenda que, en cierta medida, da algo similar a 2FA con muy poco trabajo. Hablamos de tener el puerto 993 (IMAP bajo SSL) cerrado hasta que un acceso a "https://www.example.com/sec_obscurity_imap.html" lo abra, idealmente durante un tiempo limitado.
¿Cuánta seguridad da esto? Podemos discutirlo, pero en mi experiencia, y aplico esta medida a menudo, todavía tengo que ver un intento de login causado por alguien que accede primero a una URL y luego al servicio "real". Esto sin hablar ni siquiera de securizar el acceso a la web.
Lo mejor de todo es que esto es trivial. Iptables ofrece un módulo razonablemente estándar que permite:
- Dar acceso a una IP de forma dinámica
- Mantener la IP con acceso durante un tiempo limitado
- Renovar el acceso cuando haya actividad desde la IP, y darla de baja cuando expire
Hablamos del "match" recent. No me he encontrado ninguna instalación/distribución que no lo tenga habilitado por defecto, aunque habrá casos de todo tipo.
La idea general de este match suele ser registrar una IP cuando accede a una cadena iptables, y luego denegar el acceso en base a los criterios que queramos, habitualmente relacionados con evitar denegación de servicio. Vamos a darle la vuelta. En lugar de registrar una IP accediendo a una cadena, vamos a escribir en un fichero de /proc para dar de alta la dirección, y vamos a permitir el acceso iptables a las IPs dadas de alta en ese fichero durante un tiempo. En realidad, es muy sencillo porque:
Para dar de alta una IP:
echo +127.0.0.2 > /proc/net/xt_recent/acceso_imap
Ejemplo de tabla IPTables para pertir el acceso solo a las IPs del fichero. Cuidado! Mucho cuidado con tocar un firewall sin saber lo que se está haciendo:
...
iptables -t filter -N IMAP
iptables -t filter -A INPUT -p tcp --dport 993 -j IMAP
...
iptables -t filter -A IMAP -m recent --update --name acceso_imap --reap --seconds 86400 -j ACCEPT
iptables -t filter -A IMAP -j DROP
...
Lo importante de esto es que
- --update: Revisa si la IP origen está en el listado de proc y, de estarlo, actualiza el último timestamp de acceso
- --name: La referencia al listado (al fichero) de IPs autorizadas
- --reap: Para borrar IPs viejas y mantener el listado limpio
- --seconds: Solo se hace match si una IP ha sido vista durante este número de segundos
Y, con esto, ya estaría, a falta de ir escribiendo en el fichero de /proc a partir de un acceso web.
No sé si merece la pena hablar sobre cómo escribir un fichero desde un servidor web, pero sí que creo que hace falta recordar que el usuario web no suele ser root (ni se os ocurra), y que por lo tanto no vais a poder escribir directamente en /proc/net/xt_recent/acceso_imap. Por dar una idea de implementación que puede ampliarse a otros entornos, de lo más sencilla posible:
- El servidor web escribe la IP desde la que se ha accedido, suponiendo que es la misma que va a usar IMAP después, en una ruta fuera del árbol web, pero con acceso para el usuario con el que se esté ejecutando.
- Monitorizamos el fichero vía systemd, que lanza un script, como root, cuando contenga algo:
# cat /etc/systemd/system/imap_whitelist.path
[Path]
PathChanged=/var/www/ruta_reglas_imap/accesos
[Install]
WantedBy=multi-user.target
# cat /etc/systemd/system/imap_whitelist.service
[Unit]
Description=Nueva whitelist IMAP
After=network.target
[Service]
Type=oneshot
ExecStart=/usr/local/bin/imap_whitelist.sh
# cat /usr/local/bin/imap_whitelist.sh
#!/bin/bash
IPT_WHITELIST="/proc/net/xt_recent/acceso_imap"
WEB_WHITELIST="/var/www/ruta_reglas_imap/accesos"
while read LINE
do
# Algo de control de errores vendria bien
echo +${LINE} > ${IPT_WHITELIST}
done <${WEB_WHITELIST}
> ${WEB_WHITELIST}
exit 0
Ojo, que no es más que un ejemplo sencillo. En la práctica, se puede complicar todo lo que se quiera. Es más, probablemente se debería complicar para controlar mejor los datos (las IPs), la concurrencia, .... Tened en cuenta, además, que nos hemos basado en entornos de firewall "tradicionales". Para el que quiera hacer algo más moderno, los mapas de BPF podrían servir para hacer algo similar a lo presentado aquí.
Evidentemente, no estamos haciendo doble factor, como tal, desde el punto de vista de tener dos controles de acceso a la propia aplicación pero, a cambio, ocultamos completamente el acceso general al servicio a todo el que no conozca los pasos necesarios. En este momento empezaría el debate de si la obscuridad es seguridad y todas estas cosas, aunque no creo que estemos hablando de exactamente lo mismo, particularmente si tenemos en cuenta que podemos habilitar todo tipo de mecanismos de autenticación en la web que escribe la IP en el fichero.
El objetivo de este post es hacer algo lo más sencillo posible que se pueda poner en marcha en una tarde. Por eso, no voy a escribir nada de código para la parte web. Esto no quita que no se pueda dar alguna idea sobre soluciones más completas.
Soluciones completas
Imaginad que seguimos con la idea de tener una aplicación web de cuatro lineas, quizá un formulario en el que escribir una IP, o cuatro cosas más. Sobre esto queremos ofrecer autenticación por usuario/contraseña, TOTP, Oauth, o cualquier otro método. En este caso, podemos poner algo como gluu.org (solo es un ejemplo) delante de la aplicación para ofrecer todos estos métodos. Podéis ver un ejemplo en este tutorial.
Hablando de soluciones completas, he preferido no citar nada sobre proveedores cloud, orquestadores o gestores de cualquier tipo. Confío en que de este post se pueden sacar ideas útiles para cualquier entorno.