A la hora de administrar el firewall iptables de GNU/Linux, considero que es mucho más productivo crear un script que aplique todas las reglas y políticas que deseemos en vez de trabajar en la línea de comandos añadiendo, quitando y modificando reglas.
En el caso que nos ocupa en el artículo, he realizado un script con el que se permite únicamente la navegación tanto por HTTP como por HTTPS. El principal problema con el que nos podemos encontrar a la hora de crear unas reglas de este tipo, es que los navegadores abrirán en nuestra máquina puertos registrados o dinámicos (>1024) para comunicarse con servidores remotos (sin ir más lejos, como www.google.com). Estos puertos además, serán aleatorios, por lo que crear una regla para navegación – a no ser que el firewall acepte crear reglas para aplicaciones en concreto – se puede volver tedioso.
Script de Iptables para navegación web
El siguiente script deberá ser ejecutado como root, o bien por un usuario con permisos administrativos:
#!/bin/bash # # Script para aplicar reglas del firewall Iptables (solo navegacion web) # ################################################################################# #Limpiar reglas iptables -F INPUT iptables -F FORWARD iptables -F OUTPUT #Flush chains iptables -X #Pondemos a 0 el contador de paquetes y bytes iptables -Z #Flush de la tabla NAT iptables -t nat -F #POLÍTICAS POR DEFECTO (se aplicarán a la tabla filter) Para mayor seguridad bloquearemos todo en un principio echo "Aplicando politicas..." iptables -P INPUT DROP iptables -P OUTPUT DROP iptables -P FORWARD DROP #Permitimos operatividad con localhost para servicios internos del sistema iptables -A INPUT -s 127.0.0.1 -i lo -j ACCEPT iptables -A OUTPUT -d 127.0.0.1 -o lo -j ACCEPT #Permitimos navegación por HTTP(80), HTTPS(443) iptables -A OUTPUT -j ACCEPT -o eth0 -p tcp --sport 1024:65535 -m multiport --dports 80,443 #Permitimos consultas DNS iptables -A OUTPUT -o eth0 -p udp --sport 1024:65535 --dport 53 -m state --state NEW -j ACCEPT #Permitir conexiones entrantes que estén relacionadas o establecidas anteriormente, es decir, HTTP, HTTPS Y DNS iptables -A INPUT -i eth0 -m state --state ESTABLISHED,RELATED -j ACCEPT #Guardar reglas iptables-save > /root/fwrules #Resumen echo "Configuracion final de iptables:" iptables -L -v
En líneas generales, os comento lo que realiza:
- Limpieza inicial de todas las reglas anteriormente existentes.
- Aplicar una política de denegación (DROP) por defecto para las tres cadenas principales: entrada (INPUT), salida (OUTPUT) y reenvío (FORWARD). Posteriormente voy aplicando poco a poco permisos concretos sobre qué navegación quiero permitir. El método recomendado para aplicar políticas de seguridad (no sólo en firewalls) muchas veces es éste: denegar todo e ir dando permisos restrictivos poco a poco en función de las necesidades.
- Acepto las comunicaciones locales de la máquina (127.0.0.1). Esto es básico. Para que el sistema funcione correctamente algunos procesos tienen que intercomunicar entre ellos a nivel local.
- Acepto las salidas (OUTPUT) hacia puertos (destination ports,»dports») 80 (HTTP), 443 (HTTPS) y 53 (DNS). Estos 3 puertos constituyen el eje central del firewall para permitir la navegación web, ya que cuando conectamos con un sitio web tendrá que darse una resolución DNS (53), y conectar si no es seguro por HTTP (80) o si es seguro por HTTPS (443).
- Se permite la entrada (INPUT) de las conexiones establecidas. ¿Qué quiere decir esto? Pues que no se permite ninguna conexión de entrada a nuestra máquina salvo las que se hayan iniciado (y autorizado) previamente. Y estas conexiones permitidas son las que antes te he comentado: HTTP, HTTPS y DNS.
- Para afinar un poco más, las conexiones hacia el exterior no podrán utilizar puertos de origen (source ports, «sport») protegidos (< 1024). Para navegación web no necesitamos los puertos protegidos para nada. Otra situación sería por ejemplo tuviéramos un servidor web o de correo, pero como digo no es el caso y los puertos protegidos no deben recibir ni emitir ninguna comunicación desde/hacia el exterior en nuestro caso.
- Por otro lado y finalizando, con iptables-save (que vemos en el script) guardamos la configuración en /root/fwrules. Más tarde, si nos encontramos en un sistema Debian, podremos restaurar las reglas del firewall con iptables-restore. Una manera eficiente de implementar esto es agregar la siguiente línea a /etc/rc.local (todo lo que indiquemos en este fichero se ejecutará al inicio del sistema):
iptables-restore < /root/fwrules
En Red Hat o derivadas bastará con:
/etc/init.d/iptables save
Reiniciamos:
reboot
Tras el reinicio, comprobamos que las reglas estén aplicadas ya con:
iptables -L
El script es tan personalizable como quieras. Puedes añadir tus propias reglas, como las que puse para Steam en otro artículo.
Como curiosidad, en Debian también tenéis disponible el paquete iptables-persistent que cumple precisamente esa función: hacer persistentes en el sistema las reglas de iptables.
Consideraciones sobre seguridad adicional
En algunos generadores de iptables o manuales, aparte de las reglas de firewall se aprovecha para modificar el comportamiento del kernel en sysctl.conf. No soy partidario de hacerlo mediante un script y mucho menos automatizarlo para cada inicio, por dos razones:
- Dichas modificaciones no sólo implican cuestiones de seguridad sino funcionales del sistema (si desactivamos la respuesta a ping por ejemplo, el servidor DHCP podría no detectar nuestra máquina). Además, tras las revisiones del kernel de Linux, la parametrización se lleva a cabo teniendo en cuenta la establidad y seguridad general del sistema. Cambiar un parámetro que en principio nos daría más seguridad, podría darnos más problemas futuros. Sin ir más lejos:
net.ipv4.conf.all.log_martians = 0
Suele estar desactivado. Diríamos, ¿por qué no registrar todos los paquetes «extraños»? Podríamos hacerlo, pero bastaría con que nos hicieran un flood de ese tipo de paquetes para colapsar nuestra máquina con registros más inflados que el precio de la vivienda.
Puedes encontrar la versión más actualizada de este script en mi repositorio de GitHub.