Un ensemble de règles iptables standard et sécurisé pour un serveur Web HTTP de base

15

J'ai essayé de mettre en place un script iptables de serveur de base qui fonctionnera pour la plupart des sites exécutant simplement un serveur Web de base en utilisant HTTP (S) et SSH (ports 80, 443 et 22). Après tout, la plupart des VPS n'ont besoin que de ces règles de ports de démarrage et peuvent ajouter des ports de messagerie ou de jeu plus tard selon les besoins.

Jusqu'à présent, j'ai le jeu de règles suivant et je me demandais si quelqu'un connaissait un meilleur script ou des améliorations qui pourraient être ajoutées.

*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 est l'une des parties les plus importantes de la sécurisation de votre box (voir aussi fail2ban) et pourtant il y a beaucoup de gens comme moi qui ont du mal à comprendre tout ce qui est nécessaire pour créer un pare-feu de base sécurisé pour nos serveurs.

Quel est le moyen le plus sûr d'ouvrir uniquement les ports de base nécessaires à un serveur Web?

Mise à jour: cyberciti.biz a un autre script iptables qui semble assez bon.

De plus, plutôt que d'utiliser Denyhosts ou fail2ban, vous pouvez utiliser iptables lui-même pour bloquer les mauvaises tentatives répétées de SSH .

Xeoncross
la source
Vous dites que c'est un VPS. Je suppose qu'il a également une IP LAN non? Faites-vous confiance à chaque machine de votre sous-réseau? Comment paranoïaque voulez-vous être ici, vous pouvez utiliser le filtrage OUTPUT pour sécuriser davantage votre machine. Faites-le moi savoir et je pourrai vous répondre avec ce que je vous suggère d'utiliser.
hobodave
Bon point, étant donné que la plupart des VPS sont dans une machine virtuelle avec d'autres éventuellement accessibles à partir du LAN, je dirais que ne pas leur faire confiance serait le point de départ intelligent. Si vous disposez de VPS supplémentaires, vous pouvez ajouter des règles ultérieurement pour y accéder (c'est-à-dire serveur Web dans la base de données).
Xeoncross
1
AVERTISSEMENT: si vous exécutez le script cyberciti.biz mentionné et qu'il modproben'est pas installé (ou s'il y a une autre erreur avant d'ouvrir le port 22), vous vous verrouillerez hors du serveur.
EoghanM

Réponses:

14

La façon la plus sûre de travailler avec iptables est de tout fermer et d'ouvrir uniquement ce dont vous avez besoin. Je suis un peu distrait, donc j'essaie toujours d'être aussi paresseux que possible, donc je ne fais pas d'erreurs qui peuvent conduire le serveur à ne pas être sécurisé.

J'utilise celui-ci, seulement un peu d'affectation variable doit être effectuée afin de le faire fonctionner.

  #!/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 :)

Je l'utilise depuis un certain temps, et tout type de modification sera très apprécié s'il est plus facile à administrer.

marc.riera
la source
Existe-t-il des outils populaires qui utilisent SNMP (161) sur TCP? Je pense que ces règles devraient être UDP / 161.
kubanczyk
1

Cela semble assez bon, mais vous pourriez resserrer les choses un peu plus. L'indicateur -s est l'IP source ou le nom de domaine, et vous ajoutez "-s 198.23.12.32" ou quelle que soit votre adresse IP pour n'autoriser SSH qu'à partir de votre IP source. Vous pouvez également choisir une plage d'adresses IP source en utilisant la notation de style CIDR .

Vous devez être prudent lors de la journalisation des appels refusés. L'adresse IP de votre serveur sera analysée par les robots, les script kiddies, etc., et le fichier journal pourrait devenir volumineux assez rapidement. À moins que vous n'essayiez de diagnostiquer un problème spécifique qui, selon vous, pourrait être lié à quelqu'un qui tente de briser votre pare-feu, je supprimerais cette option.

Vous pouvez également lier fail2ban à iptables pour un pseudo-IDS. fail2ban analysera vos fichiers journaux et peut bloquer une adresse IP s'ils tentent de pénétrer de force dans votre système. Par exemple, si une certaine adresse IP ne parvient pas à se connecter à SSH 5 fois, vous pouvez les verrouiller pendant une journée entière. Il fonctionne également sur FTP et beaucoup d'autres (y compris les mauvais robots qui frappent Apache). Je l'utilise sur tous mes serveurs pour fournir un coussin supplémentaire contre les attaques par force brute.

Alan Ivey
la source
J'utilise en fait DenyHosts car il économise environ 15 Mo sur fail2ban. Cependant, fail2ban est plus puissant et fonctionne avec de nombreuses applications (pas seulement SSH comme DenyHosts). Étant donné que les attaquants sont interdits, dois-je tout de même m'inquiéter du remplissage rapide des fichiers journaux? Existe-t-il un moyen de faire pivoter les fichiers lorsqu'ils sont pleins? Si je désactive la connexion à fail2ban, les Denyhosts / Fail2ban auront-ils toujours des entrées de journal à analyser? De plus, l'option source serait bonne pour certaines personnes - mais comme je vise un ensemble de règles par défaut, les gens comme moi qui se déplacent beaucoup ne peuvent pas utiliser cette option.
Xeoncross
@Xeoncross: DenyHosts est une imo de pile fumante. Je l'ai fait fonctionner sur une machine qui recevait constamment des tentatives d'intrusion de la part des Chinois. Au cours de la période de quelques mois /etc/hosts.deny a grandi pour contenir quelques milliers d'adresses IP, ce qui a entraîné l'épuisement des ressources de sshd sur la boîte, augmentant la charge jusqu'à 60+ sur une seule machine CPU. Je suis passé à fail2ban et je n'ai jamais regardé en arrière.
hobodave
@hobodave Je viens de commencer avec DenyHosts donc je garderai cet esprit comme la première chose à changer lorsque cela deviendra un problème.
Xeoncross
1
@Xeoncross si vous souhaitez faire pivoter le journal iptables, vous pouvez écrire votre propre script logrotate.d pour cela. Jetez un œil à /etc/logrotate.d et copiez-en un autre et changez le nom du fichier journal et il sera tourné avec d'autres fichiers journaux. La page de manuel de logrotate explique les différentes options.
Alan Ivey
1

Jetez un œil à Shorewall. La configuration par défaut à interface unique serait un bon point de départ. Il est facile à configurer et possède des macros pour des choses comme SSH et l'accès Web. Il peut être configuré pour verrouiller le serveur au niveau souhaité lorsque le pare-feu est arrêté. Avec Shorewall-lite, vous pouvez exécuter une construction de pare-feu sur un autre serveur. La journalisation est facile à configurer au niveau souhaité.

Pour un serveur HTTP de base, vous souhaitez ouvrir l'accès entrant au port 80 et au port 443 si vous utilisez HTTPS. L'accès entrant SSH à partir de quelques adresses restreintes est généralement souhaité. Vous pouvez également verrouiller l'accès sortant. Ouvrez le pare-feu uniquement aux serveurs et services requis. NTP et DNS doivent être ouverts, ainsi qu'un canal pour récupérer les correctifs.

BillThor
la source
1

Je dirais que c'est un assez bon pare-feu, sauf qu'il est conçu pour arrêter le trafic entrant, et non pas axé sur le trafic sortant ou sortant. Dans de nombreux cas, il est tout aussi important de se concentrer sur les connexions sortantes d'une boîte que celles entrantes. Dans le cas malheureux où la machine est réellement exploitée, il serait bien de pouvoir empêcher le téléchargement de kits racine supplémentaires, ou la connexion à des nœuds de commande et de contrôle, ou autre.

BillThor a commencé à en parler ci-dessus, mais je ne fais que répondre avec des exemples spécifiques. L'une des bonnes choses à propos d'iptables est qu'il peut se souvenir de l'état de la connexion, cela peut avoir des implications sur les performances des sites très fréquentés, mais vous pouvez modifier votre accès entrant sur http / https pour autoriser uniquement la réponse sur les connexions établies par exemple, ou limiter spécifiquement certaines zones non privilégiées utilisateurs d'avoir un accès sortant du tout. Vos règles sortantes auraient alors des clauses RELATED, ESTABLISHED qui empêcheraient toute une série d'attaques auxiliaires et ralentiraient celles qui nécessitent une étape secondaire pour exploiter réellement une boîte, ce qui est très courant.

Enfin, je dirais qu'il est préférable de définir votre politique iptables -P DROP plutôt que d'avoir un REJECT en annexe à la fin. C'est principalement une question de préférence, mais peut réduire les erreurs lors de l'ajout aux chaînes avec des règles existantes au lieu d'insérer ou de vider / réinitialiser.

MattyB
la source
Je devrais donc changer -A INPUT -j REJECTpour -A INPUT -P DROP?
Xeoncross