Bezpieczny, standardowy zestaw reguł iptables dla podstawowego serwera HTTP (s)

15

Próbowałem stworzyć podstawowy skrypt iptables serwera, który będzie działał w przypadku większości witryn z uruchomionym podstawowym serwerem WWW za pomocą HTTP (S) i SSH (porty 80, 443 i 22). W końcu większość VPS potrzebuje tylko tych początkowych reguł portów i może w razie potrzeby dodać porty poczty lub gier.

Do tej pory mam następujący zestaw reguł i zastanawiałem się, czy ktoś wie o lepszym skrypcie lub ulepszeniach, które można by dodać.

*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 jest jedną z najważniejszych części zabezpieczania twojego urządzenia (patrz także fail2ban), a jednak wiele osób takich jak ja ma problemy ze zrozumieniem wszystkiego, co wymaga bezpiecznej podstawowej zapory ogniowej dla naszych serwerów.

Jaki jest najbezpieczniejszy sposób otwarcia tylko podstawowych portów potrzebnych do serwera WWW?

Aktualizacja: cyberciti.biz ma kolejny skrypt iptables, który wygląda całkiem nieźle.

Ponadto zamiast używać Denyhosts lub fail2ban, możesz użyć samego iptables do blokowania złych, powtarzających się prób SSH .

Xeoncross
źródło
Mówisz, że to VPS. Zakładam, że ma również adres IP LAN, prawda? Czy ufasz każdej maszynie w swojej podsieci? Jak bardzo chcesz być paranoikiem, możesz użyć filtrowania WYJŚĆ, aby dodatkowo zabezpieczyć swój komputer. Daj mi znać, a mogę odpowiedzieć na to, co sugeruję, abyś użył.
hobodave
Dobra uwaga, biorąc pod uwagę, że większość VPS jest na maszynie wirtualnej, a inne są prawdopodobnie dostępne z sieci LAN. Powiedziałbym, że brak zaufania byłby dobrym miejscem startowym. Jeśli masz dodatkowy VPS, możesz później dodać reguły, aby uzyskać do nich dostęp (np. Serwer WWW do bazy danych).
Xeoncross,
1
OSTRZEŻENIE: jeśli wykonasz wspomniany skrypt cyberciti.biz i modprobenie zostanie zainstalowany (lub wystąpi inny błąd przed otwarciem portu 22), zablokujesz się na serwerze.
EoghanM,

Odpowiedzi:

14

Najbezpieczniejszym sposobem pracy z iptables jest zamknięcie wszystkiego i otwarcie tylko tego, czego potrzebujesz. Jestem trochę rozkojarzony, więc zawsze staram się być tak leniwy, jak to możliwe, więc nie popełniam błędów, które mogą prowadzić do niepewności serwera.

Używam tego, tylko odrobina zmiennego przypisania musi być wykonana, aby działało.

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

Używam go od jakiegoś czasu i wszelkie modyfikacje będą mile widziane, jeśli ułatwi to administrowanie.

marc.riera
źródło
Czy są jakieś popularne narzędzia korzystające z SNMP (161) przez TCP? Myślę, że tymi zasadami powinny być UDP / 161.
kubańczyk
1

Wygląda to całkiem nieźle, ale można trochę bardziej zaostrzyć. Flaga -s to źródłowy adres IP lub nazwa domeny i dodajesz „-s 198.23.12.32” lub dowolny inny adres IP, aby zezwolić na SSH tylko ze źródłowego adresu IP. Możesz także wybrać zakres źródłowych adresów IP za pomocą notacji w stylu CIDR .

Należy zachować ostrożność podczas rejestrowania odrzuconych połączeń. Adres IP twojego serwera zostanie przeskanowany przez boty, dzieciaki skryptów itp., A plik dziennika może się szybko powiększyć. Jeśli nie próbujesz zdiagnozować konkretnego problemu, który Twoim zdaniem może być związany z osobą próbującą złamać zaporę, usunę tę opcję.

Możesz także powiązać fail2ban z iptables dla pseudo-IDS. fail2ban przeskanuje twoje pliki dziennika i może zablokować adres IP, jeśli spróbują przedostać się do twojego systemu. Na przykład, jeśli określony adres IP nie zaloguje się 5 razy do SSH, możesz je zablokować na cały dzień. Działa również na FTP i wielu innych (w tym złe boty uderzające w Apache). Używam go na wszystkich moich serwerach, aby zapewnić dodatkową ochronę przed atakami brutalnej siły.

Alan Ivey
źródło
Właściwie używam DenyHosts, ponieważ oszczędza około 15 MB ponad fail2ban. Jednak fail2ban jest bardziej wydajny i działa z wieloma aplikacjami (nie tylko SSH, jak DenyHosts). Biorąc pod uwagę, że atakujący zostali zbanowani, czy powinienem nadal martwić się, że pliki dziennika będą się szybko zapełniać? Czy istnieje sposób na obracanie plików, gdy się zapełni? Jeśli wyłączę logowanie w fail2ban, czy Denyhosts / Fail2ban nadal będzie mieć wpisy dziennika do skanowania? Również opcja źródłowa byłaby dobra dla niektórych osób - ale ponieważ dążę do domyślnego zestawu reguł, ludzie tacy jak ja, którzy często się poruszają, nie mogą korzystać z tej opcji.
Xeoncross,
@Xeoncross: DenyHosts to imo na parze. Miałem go uruchomionego na jednej maszynie, która ciągle otrzymywała próby włamań od Chińczyków. W ciągu kilku miesięcy /etc/hosts.deny wyrósł na kilka tysięcy adresów IP, w którym to momencie sshd wyczerpał zasoby na pudełku, zwiększając obciążenie do ponad 60 na jednym komputerze z procesorem. Przełączyłem się na fail2ban i nigdy nie oglądałem się za siebie.
hobodave
@hobodave Właśnie zacząłem od DenyHosts, więc zachowam ten umysł jako pierwszą rzecz, która się zmieni, gdy stanie się to problemem.
Xeoncross,
1
@Xeoncross, jeśli chcesz obrócić dziennik iptables, możesz napisać dla niego własny skrypt logrotate.d. Spójrz na /etc/logrotate.d i skopiuj kolejny i zmień nazwę pliku dziennika, a zostanie on obrócony wraz z innymi plikami dziennika. Strona podręcznika dla programu logrotate wyjaśnia różne opcje.
Alan Ivey
1

Spójrz na Shorewall. Dobra domyślna konfiguracja pojedynczego interfejsu byłaby dobrym punktem wyjścia. Jest łatwy w konfiguracji i zawiera makra dla takich rzeczy jak SSH i dostęp do sieci. Można go skonfigurować tak, aby blokował serwer do pożądanego poziomu, gdy zapora jest zamknięta. Dzięki Shorewall-lite możesz uruchomić kompilację zapory ogniowej na innym serwerze. Logowanie jest łatwe do skonfigurowania do pożądanego poziomu.

W przypadku podstawowego serwera HTTP chcesz otworzyć dostęp przychodzący do portu 80 i portu 443, jeśli używasz HTTPS. Dostęp przychodzący SSH z kilku zastrzeżonych adresów jest zwykle pożądany. Możesz także zablokować dostęp wychodzący. Otwórz zaporę tylko na wymagane serwery i usługi. NTP i DNS powinny zostać otwarte, a także kanał do pobierania poprawek.

BillThor
źródło
1

Powiedziałbym, że jest to całkiem dobra zapora ogniowa, z wyjątkiem tego, że ma na celu zatrzymanie ruchu przychodzącego, a nie koncentruje się na ruchu wyjściowym lub wychodzącym. W wielu przypadkach równie ważne jest skupienie się na połączeniach wychodzących ze skrzynki, jak te przychodzące. W niefortunnym przypadku, gdy maszyna jest faktycznie wykorzystywana, fajnie byłoby móc uniemożliwić pobieranie dodatkowych zestawów root, łączenie się z węzłami dowodzenia i kontroli lub cokolwiek innego.

BillThor zaczął o tym mówić powyżej, ale odpowiadam tylko konkretnymi przykładami. Jedną z fajnych rzeczy w iptables jest to, że zapamiętuje stan połączenia, może to mieć wpływ na wydajność w witrynach o dużym natężeniu ruchu, ale można zmienić dostęp przychodzący na http / https, aby zezwolić na odpowiedź tylko na ustanowione połączenia, lub w szczególności ograniczyć niektóre nieuprzywilejowane użytkownicy w ogóle nie mają dostępu wychodzącego. Wtedy twoje reguły wychodzące miałyby POWIĄZANE, USTANOWIONE klauzule, które zapobiegłyby całemu szeregowi ataków pomocniczych i spowolniłyby te, które wymagają etapu drugiego do faktycznego wykorzystania skrzynki, co jest bardzo powszechne.

Na koniec powiedziałbym, że lepiej jest ustawić swoją politykę iptables -P DROP, niż mieć dołączony REJECT na końcu. Jest to głównie kwestia preferencji, ale może zmniejszyć liczbę błędów podczas dołączania do łańcuchów z istniejącymi regułami zamiast wstawiania lub opróżniania / resetowania.

MattyB
źródło
Więc powinienem zmienić -A INPUT -j REJECTna -A INPUT -P DROP?
Xeoncross,