Un conjunto de reglas iptables seguro y estándar para un servidor web HTTP básico

15

He estado tratando de armar un script básico de iptables del servidor que funcione para la mayoría de los sitios que solo ejecutan un servidor web básico usando HTTP (S) y SSH (puertos 80, 443 y 22). Después de todo, la mayoría de los VPS solo necesitan estas reglas de puertos de inicio y pueden agregar puertos de correo o juegos más tarde según sea necesario.

Hasta ahora tengo el siguiente conjunto de reglas y me preguntaba si alguien sabe de un mejor script o cualquier mejora que pueda agregarse.

*filter

#  Allows all loopback (lo0) traffic and drop all traffic to 127/8 that doesn't use lo0
-A INPUT -i lo -j ACCEPT
-A INPUT ! -i lo -d 127.0.0.0/8 -j REJECT

#  Accepts all established inbound connections
-A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

#  Allows all outbound traffic
#  You can modify this to only allow certain traffic
-A OUTPUT -j ACCEPT

# Allows HTTP and HTTPS connections from anywhere (the normal ports for websites)
-A INPUT -p tcp --dport 80 -j ACCEPT
-A INPUT -p tcp --dport 443 -j ACCEPT

#  Allows SSH connections (only 4 attempts by an IP every 3 minutes, drop the rest)
-A INPUT -p tcp -m tcp --dport 22 -m state --state NEW -m recent --set --name DEFAULT --rsource
-A INPUT -p tcp -m tcp --dport 22 -m state --state NEW -m recent --update --seconds 180 --hitcount 4 --name DEFAULT --rsource -j DROP
-A INPUT -p tcp -m state --state NEW --dport 22 -j ACCEPT

# Allow ping
-A INPUT -p icmp -m icmp --icmp-type 8 -j ACCEPT

# log iptables denied calls
-A INPUT -m limit --limit 5/min -j LOG --log-prefix "iptables denied: " --log-level 7

# Reject all other inbound - default deny unless explicitly allowed policy
-A INPUT -j REJECT
-A FORWARD -j REJECT

COMMIT

iptables es una de las partes más importantes de asegurar su caja (también vea fail2ban) y, sin embargo, hay muchas personas como yo que tienen problemas para comprender todo lo que implica crear un firewall básico seguro para nuestros servidores.

¿Cuál es la forma más segura de abrir solo los puertos básicos necesarios para un servidor web?

Actualización: cyberciti.biz tiene otro script de iptables que se ve bastante bien.

Además, en lugar de usar Denyhosts o fail2ban, podría usar iptables para bloquear intentos fallidos repetidos en SSH .

Xeoncross
fuente
Dices que es un VPS. Supongo que también tiene una IP de LAN, ¿verdad? ¿Confía en todas las máquinas de su subred? Qué tan paranoico quieres estar aquí, puedes usar el filtro de SALIDA para asegurar aún más tu máquina. Avísame y puedo responder con lo que te sugiero que uses.
hobodave
Buen punto, dado que la mayoría de los VPS están en una VM con otros posiblemente accesibles desde LAN, diría que no confiar en ellos sería el punto de partida inteligente. Si tiene VPS adicionales, puede agregar reglas más tarde para acceder a ellas (es decir, servidor web a la base de datos).
Xeoncross
1
ADVERTENCIA: si ejecuta el script cyberciti.biz mencionado y modprobeno está instalado (o si hay algún otro error antes de abrir el puerto 22), se bloqueará del servidor.
EoghanM

Respuestas:

14

La forma más segura de trabajar con iptables es cerrar todo y solo abrir lo que necesita. Estoy un poco distraído, así que siempre trato de ser lo más vago posible, para no cometer errores que puedan hacer que el servidor no sea seguro.

Utilizo este, solo se debe hacer un poco de asignación de variables para que funcione.

  #!/bin/bash +x

  # first author: marcos de vera
  # second: joan marc riera

  ip=/sbin/iptables
  mriera="xx.xx.xx.xx"
  nsancho="yy.yy.yy.yy"
  admins="$mriera $nsancho "
  sshers=""
  mysqlrs="zz.zz.zz.zz/23"
  snmprs="uu.uu.uu.uu"
  tcpservices="80 443 22"
  udpservices=""

  # Firewall script for servername

  echo -n ">> Applying iptables rules... "

  ## flushing...
  $ip -F
  $ip -X
  $ip -Z
  $ip -t nat -F

  # default: DROP!
  $ip -P INPUT DROP
  $ip -P OUTPUT DROP
  $ip -P FORWARD DROP

  # filtering...

  # localhost: free pass!
  $ip -A INPUT -i lo -j ACCEPT
  $ip -A OUTPUT -o lo -j ACCEPT

  # administration ips: free pass!
  for admin in $admins ; do
      $ip -A INPUT -s $admin -j ACCEPT
      $ip -A OUTPUT -d $admin -j ACCEPT
  done

  # allow ssh access to sshers
  for ssher in $sshers ; do
      $ip -A INPUT -s $ssher -p tcp -m tcp --dport 22 -j ACCEPT
      $ip -A OUTPUT -d $ssher -p tcp -m tcp --sport 22 -j ACCEPT
  done

  # allow access to mysql port to iReport on sugar

  for mysql in $mysqlrs ; do
      $ip -A INPUT -s $mysql -p tcp -m tcp --dport 3306 -j ACCEPT
      $ip -A OUTPUT -d $mysql -p tcp -m tcp --sport 3306 -j ACCEPT
      $ip -A INPUT -s $mysql -p udp -m udp --dport 3306 -j ACCEPT
      $ip -A OUTPUT -d $mysql -p udp -m udp --sport 3306 -j ACCEPT
  done


  # allowed services
  for service in $tcpservices ; do
      $ip -A INPUT -p tcp -m tcp --dport $service -j ACCEPT
      $ip -A OUTPUT -p tcp -m tcp --sport $service -m state --state RELATED,ESTABLISHED -j ACCEPT
  done
  for service in $udpservices ; do
      $ip -A INPUT -p udp -m udp --dport $service -j ACCEPT
      $ip -A OUTPUT -p udp -m udp --sport $service -m state --state RELATED,ESTABLISHED -j ACCEPT
  done

  $ip -A INPUT -j LOG --log-level 4
  # VAS and VGP
  #88 tcp udp
  #389 tcp ldap queries , udp ldap ping
  #464 tcp upd kerberos
  #3268 tcp global catalog access
  for dc in ip.ip.ip.ip ; do # our dc servers for some ldap auth
      vas=88
      $ip -A INPUT -s $dc -p tcp -m tcp --dport $vas -j ACCEPT
      $ip -A OUTPUT -d $dc -p tcp -m tcp --dport $vas -j ACCEPT
      $ip -A INPUT -s $dc -p udp -m udp --dport $vas -j ACCEPT
      $ip -A OUTPUT -d $dc -p udp -m udp --dport $vas -j ACCEPT
      ldap=389
      $ip -A INPUT -s $dc -p tcp -m tcp --dport $ldap -j ACCEPT
      $ip -A OUTPUT -d $dc -p tcp -m tcp --dport $ldap -j ACCEPT
      $ip -A INPUT -s $dc -p udp -m udp --dport $ldap -j ACCEPT
      $ip -A OUTPUT -d $dc -p udp -m udp --dport $ldap -j ACCEPT
      kpasswd=464
      $ip -A INPUT -s $dc -p tcp -m tcp --dport $kpasswd -j ACCEPT
      $ip -A OUTPUT -d $dc -p tcp -m tcp --dport $kpasswd -j ACCEPT
      $ip -A INPUT -s $dc -p udp -m udp --dport $kpasswd -j ACCEPT
      $ip -A OUTPUT -d $dc -p udp -m udp --dport $kpasswd -j ACCEPT
      gca=3268
      $ip -A INPUT -s $dc -p tcp -m tcp --dport $gca -j ACCEPT
      $ip -A OUTPUT -d $dc -p tcp -m tcp --dport $gca -j ACCEPT
      vgp=445
      $ip -A INPUT -s $dc -p tcp -m tcp --dport $vgp -j ACCEPT
      $ip -A OUTPUT -d $dc -p tcp -m tcp --dport $vgp -j ACCEPT
  done


  # allow the machine to browse the internet
  $ip -A INPUT -p tcp -m tcp --sport 80 -m state --state RELATED,ESTABLISHED -j ACCEPT
  $ip -A OUTPUT -p tcp -m tcp --dport 80 -j ACCEPT
  $ip -A INPUT -p tcp -m tcp --sport 443 -m state --state RELATED,ESTABLISHED -j ACCEPT
  $ip -A OUTPUT -p tcp -m tcp --dport 443 -j ACCEPT

  $ip -A INPUT -p tcp -m tcp --sport 8080 -m state --state RELATED,ESTABLISHED -j ACCEPT
  $ip -A OUTPUT -p tcp -m tcp --dport 8080 -j ACCEPT


  # don't forget the dns...
  $ip -A INPUT -p udp -m udp --sport 53 -j ACCEPT
  $ip -A OUTPUT -p udp -m udp --dport 53 -j ACCEPT
  $ip -A INPUT -p tcp -m tcp --sport 53 -j ACCEPT
  $ip -A OUTPUT -p tcp -m tcp --dport 53 -j ACCEPT

  # ... neither the ntp... (hora.rediris.es)
  #$ip -A INPUT -s 130.206.3.166 -p udp -m udp --dport 123 -j ACCEPT
  #$ip -A OUTPUT -d 130.206.3.166 -p udp -m udp --sport 123 -j ACCEPT

  $ip -A INPUT -p udp -m udp --dport 123 -j ACCEPT
  $ip -A OUTPUT -p udp -m udp --sport 123 -j ACCEPT


  # and last but not least, the snmp access
  for monitor in $snmprs ; do
      $ip -A INPUT -s $monitor -p tcp -m tcp --sport 161 -j ACCEPT   # monitoring service
      $ip -A OUTPUT -d $monitor -p tcp -m tcp --dport 161 -j ACCEPT  # monitoring service
  end
  # outgoing SMTP
  $ip -A INPUT -p tcp -m tcp --sport 25 -j ACCEPT
  $ip -A OUTPUT -p tcp -m tcp --dport 25 -j ACCEPT


  # temporary backup if we change from DROP to ACCEPT policies
  $ip -A INPUT -p tcp -m tcp --dport 1:1024 -j DROP
  $ip -A INPUT -p udp -m udp --dport 1:1024 -j DROP


  echo "OK. Check rules with iptables -L -n"

  # end :)

Lo he estado usando durante algún tiempo, y cualquier tipo de modificación será muy apreciada si facilita la administración.

marc.riera
fuente
¿Hay alguna herramienta popular que use SNMP (161) sobre TCP? Creo que estas reglas deberían ser UDP / 161.
kubanczyk
1

Esto se ve bastante bien, pero podría ajustar las cosas un poco más. El indicador -s es la IP de origen o el nombre de dominio, y agrega "-s 198.23.12.32" o lo que sea que su dirección IP permita solo SSH desde su IP de origen. También puede elegir un rango de IP de origen utilizando la notación de estilo CIDR .

Debe tener precaución al registrar llamadas denegadas. La dirección IP de su servidor será escaneada por bots, script kiddies, etc., y el archivo de registro podría agrandarse bastante rápido. A menos que intente diagnosticar un problema específico que cree que podría estar relacionado con alguien que intenta romper su firewall, eliminaría esta opción.

También puede vincular fail2ban a iptables para un pseudo-IDS. fail2ban escaneará sus archivos de registro y puede bloquear una IP si intentan forzar su entrada en su sistema. Por ejemplo, si una determinada dirección IP no puede iniciar sesión en SSH 5 veces, puede bloquearla durante un día entero. También funciona en FTP y en muchos otros (incluidos los robots malos que golpean a Apache). Lo uso en todos mis servidores para proporcionar algo de protección adicional contra los ataques de fuerza bruta.

Alan Ivey
fuente
De hecho, uso DenyHosts ya que ahorra 15 MB más o menos en fail2ban. Sin embargo, fail2ban es más potente y funciona con muchas aplicaciones (no solo SSH como DenyHosts). Dado que los atacantes están prohibidos, ¿debería preocuparme si los archivos de registro se llenan demasiado rápido? ¿Hay alguna forma de rotar los archivos cuando se llenan? Si desactivo el inicio de sesión en fail2ban, ¿Denyhosts / Fail2ban todavía tendrá entradas de registro para escanear? Además, la opción de fuente sería buena para algunas personas, pero como estoy apuntando a un conjunto de reglas predeterminado, las personas como yo que se mueven mucho no pueden usar esa opción.
Xeoncross
@ Xeoncross: DenyHosts es una pila de vapor imo. Lo tenía ejecutándose en una máquina que constantemente recibía intentos de intrusión de los chinos. En el transcurso de unos meses, /etc/hosts.deny creció hasta tener unos pocos miles de IPs, momento en el que causó que sshd agotara los recursos en la caja, aumentando la carga hasta 60+ en una sola máquina con CPU. Cambié a fail2ban y nunca miré hacia atrás.
hobodave
@hobodave Acabo de comenzar con DenyHosts, así que tendré esta mente como la primera cosa que cambiar cuando esto se convierta en un problema.
Xeoncross
1
@Xeoncross si desea rotar el registro de iptables, puede escribir su propio script logrotate.d para ello. Eche un vistazo a /etc/logrotate.d y copie otro y cambie el nombre del archivo de registro y se rotará con otros archivos de registro. La página del manual para logrotate explica las diversas opciones.
Alan Ivey
1

Echa un vistazo a Shorewall. La configuración predeterminada de la interfaz única sería un buen punto de partida. Es fácil de configurar y tiene macros para cosas como SSH y acceso web. Se puede configurar para bloquear el servidor al nivel deseado cuando se apaga el firewall. Con Shorewall-lite, puede ejecutar una compilación de firewall en otro servidor. El registro es fácil de configurar al nivel deseado.

Para un servidor HTTP básico, desea abrir el acceso entrante al puerto 80 y al puerto 443 si usa HTTPS. Generalmente se desea acceso entrante SSH desde algunas direcciones restringidas. Es posible que también desee bloquear el acceso saliente. Abra el firewall solo para los servidores y servicios necesarios. Se deben abrir NTP y DNS, así como un canal para buscar parches.

BillThor
fuente
1

Diría que este es un cortafuegos bastante bueno, excepto que está orientado a detener el tráfico entrante y no está enfocado en la salida o el tráfico saliente. En muchos casos, es tan importante centrarse en las conexiones salientes desde una caja como aquellas entrantes. En el desafortunado caso de que la máquina sea realmente explotada, sería bueno poder evitar la descarga de kits raíz adicionales, o conectarse a nodos de comando y control, o lo que sea.

BillThor comenzó a hablar sobre esto anteriormente, pero solo estoy respondiendo con ejemplos específicos. Una de las cosas buenas de iptables es que puede recordar el estado de conexión, esto puede tener implicaciones de rendimiento en sitios con mucho tráfico, pero podría cambiar su acceso entrante en http / https para permitir solo la respuesta en conexiones establecidas, por ejemplo, o limitar específicamente ciertos no privilegiados usuarios de tener acceso saliente en absoluto. Entonces, sus reglas de salida tendrían cláusulas RELACIONADAS, ESTABLECIDAS que evitarían una gran cantidad de ataques auxiliares y ralentizarían los que requieren una etapa secundaria para explotar una caja, lo cual es muy común.

Finalmente, diría que es mejor configurar su política de iptables -P DROP en lugar de tener un RECHAZO adjunto al final. Es sobre todo una cuestión de preferencia, pero puede reducir los errores al agregar cadenas con reglas existentes en lugar de insertar o vaciar / restablecer.

Matty B
fuente
Así que debería cambiar -A INPUT -j REJECTa -A INPUT -P DROP?
Xeoncross