Назад | Перейти на главную страницу

iptables Советы и хитрости

Я уверен, что системные администраторы Linux хорошо знакомы с iptables, пользовательский интерфейс к netfilter структура фильтрации пакетов.

Итак, этот «Вопрос» предназначен для Сообщество вики для сбора различных битов и кусочков iptables мудрость. Нет ничего слишком обычного или неясного. Публикуйте все, что вы знаете, что поможет другим максимально эффективно использовать iptables.

Использование белого и черного списка с iptables

#!/bin/bash

WHITELIST=/whitelist.txt
BLACKLIST=/blacklist.txt

#THIS WILL CLEAR ALL EXISTING RULES!
echo 'Clearing all rules'
iptables -F

#
## Whitelist
#

for x in `grep -v ^# $WHITELIST | awk '{print $1}'`; do
        echo "Permitting $x..."
        $IPTABLES -A INPUT -t filter -s $x -j ACCEPT
done

#
## Blacklist
#

for x in `grep -v ^# $BLACKLIST | awk '{print $1}'`; do
        echo "Denying $x..."
        $IPTABLES -A INPUT -t filter -s $x -j DROP
done

Скрипт для открытия портов

#!/bin/bash
ALLOWEDTCP="80 3128 3784"
ALLOWEDUDP="3128 3784"

#
## Permitted Ports
#

for port in $ALLOWEDTCP; do
       echo "Accepting port TCP $port..."
       $IPTABLES -A INPUT -t filter -p tcp --dport $port -j ACCEPT
done

for port in $ALLOWEDUDP; do
        echo "Accepting port UDP $port..."
        $IPTABLES -A INPUT -t filter -p udp --dport $port -j ACCEPT
done

Блокировка сканирования портов

# Attempt to block portscans
# Anyone who tried to portscan us is locked out for an entire day.
iptables -A INPUT   -m recent --name portscan --rcheck --seconds 86400 -j DROP
iptables -A FORWARD -m recent --name portscan --rcheck --seconds 86400 -j DROP

# Once the day has passed, remove them from the portscan list
iptables -A INPUT   -m recent --name portscan --remove
iptables -A FORWARD -m recent --name portscan --remove

# These rules add scanners to the portscan list, and log the attempt.
iptables -A INPUT   -p tcp -m tcp --dport 139 -m recent --name portscan --set -j LOG --log-prefix "Portscan:"
iptables -A INPUT   -p tcp -m tcp --dport 139 -m recent --name portscan --set -j DROP

iptables -A FORWARD -p tcp -m tcp --dport 139 -m recent --name portscan --set -j LOG --log-prefix "Portscan:"
iptables -A FORWARD -p tcp -m tcp --dport 139 -m recent --name portscan --set -j DROP

Поддельные / недействительные пакеты

# Reject spoofed packets
# These adresses are mostly used for LAN's, so if these would come to a WAN-only server, drop them.
iptables -A INPUT -s 10.0.0.0/8 -j DROP
iptables -A INPUT -s 169.254.0.0/16 -j DROP
iptables -A INPUT -s 172.16.0.0/12 -j DROP
iptables -A INPUT -s 127.0.0.0/8 -j DROP

#Multicast-adresses.
iptables -A INPUT -s 224.0.0.0/4 -j DROP
iptables -A INPUT -d 224.0.0.0/4 -j DROP
iptables -A INPUT -s 240.0.0.0/5 -j DROP
iptables -A INPUT -d 240.0.0.0/5 -j DROP
iptables -A INPUT -s 0.0.0.0/8 -j DROP
iptables -A INPUT -d 0.0.0.0/8 -j DROP
iptables -A INPUT -d 239.255.255.0/24 -j DROP
iptables -A INPUT -d 255.255.255.255 -j DROP

# Drop all invalid packets
iptables -A INPUT -m state --state INVALID -j DROP
iptables -A FORWARD -m state --state INVALID -j DROP
iptables -A OUTPUT -m state --state INVALID -j DROP

Блокировать атаки смурфов

# Stop smurf attacks
iptables -A INPUT -p icmp -m icmp --icmp-type address-mask-request -j DROP
iptables -A INPUT -p icmp -m icmp --icmp-type timestamp-request -j DROP
iptables -A INPUT -p icmp -m icmp -j DROP

# Drop excessive RST packets to avoid smurf attacks
iptables -A INPUT -p tcp -m tcp --tcp-flags RST RST -m limit --limit 2/second --limit-burst 2 -j ACCEPT

Блокировать ICMP (он же пинг)

# Don't allow pings through
iptables -A INPUT -p icmp -m icmp --icmp-type 8 -j DROP

Оптимизируйте производительность netfilter с помощью ipset

Если вы напишете много аналогичных правил, основанных на простом IP, порте или обоих, рассмотрите возможность использования ipset для оптимизации производительности netfilter.

Например:

iptables -s 192.168.1.11 -j ACCEPT
iptables -s 192.168.1.27 -j ACCEPT
iptables -s 192.168.1.44 -j ACCEPT
... hundreds of similar rules ...
iptables -s 192.168.251.177 -j ACCEPT

Это означает, что пакет с адресом источника 192.168.251.177 должен сначала пройти через сотни правил, прежде чем он сможет получить свой вердикт ПРИНЯТЬ.

Конечно, опытные системные администраторы разбивают правила по подсетям. Но это по-прежнему означает сотни правил.

ipset для спасения!

Сначала определите набор IP-адресов ipmap тип:

ipset -N Allowed_Hosts ipmap --network 192.168.0.0/16

Затем заполните его адресами:

for ip in $LIST_OF_ALLOWED_IP; do ipset -A Allowed_Hosts $ip; done

Наконец, замените сотни правил iptables выше на один правило:

iptables -m set --match-set Allowed_Hosts src -j ACCEPT

Когда приходит пакет, netfilter выполнит очень быстрый поиск по битовой карте для IP-адреса источника (src) пакета по Allowed_Hosts IP Set. Все пакеты, поступающие из 192.168.0.0/16, будут один правило. И поверьте мне, что поиск по растровому изображению как минимум на два порядка быстрее, чем выполнение сотен проверок правил iptables.

ipset не ограничивается IP-адресами. Он также может соответствовать на основе портов, кортежа IP-портов, адресов сети / подсети, кортежа IP-MAC и т. Д. И т. Д. И он может соответствовать этим критериям в качестве источника или назначения или их комбинации (в случае кортежей).

И наконец, с ipset вы можете автоматически помещать IP-адреса в черные / белые списки. Эти черные / белые списки также могут «устареть», таким образом, автоматически удаляя IP-адрес по прошествии настраиваемого количества времени.

Пожалуйста, обратитесь к ipsetстраница руководства пользователя Больше подробностей.

ОЧЕНЬ ВАЖНОЕ ПРИМЕЧАНИЕ:

Некоторые дистрибутивы Linux могут не иметь "из коробки" поддержку ipset (например, у Ubuntu 10.04 была эта проблема). В этих системах один из способов - установить ipset из исходного кода.

Вместо этого загрузите ipsetИсточник со своего веб-сайта: http://ipset.netfilter.org/install.html

В качестве альтернативы, если вы используете xtables-addons, ipset является включены в его источник: http://xtables-addons.sourceforge.net/

Добавьте комментарии к своим правилам:

-m comment --comment "Comments help to read output of iptables -nvL"

Блокировать известные TCP-атаки

Добавьте следующие правила, желательно в -t raw -A PREROUTING

-p tcp --tcp-flags FIN,SYN FIN,SYN -j DROP
-p tcp --tcp-flags SYN,RST SYN,RST -j DROP
-p tcp --tcp-flags FIN,SYN,RST,PSH,ACK,URG FIN,PSH,URG -j DROP
-p tcp --tcp-flags FIN,SYN,RST,PSH,ACK,URG FIN -j DROP
-p tcp --tcp-flags FIN,SYN,RST,PSH,ACK,URG NONE -j DROP
-p tcp --tcp-flags FIN,SYN,RST,PSH,ACK,URG FIN,SYN,RST,PSH,ACK,URG -j DROP

Блокируемые атаки:

  • SYN-FIN атака
  • SYN-RST атака
  • Рождественская атака
  • nmap FIN сканирование
  • Атака NULLflags
  • Атака ALLflags

(смело редактируйте названия атак выше)

Включение NAT

  1. echo 1 > /proc/sys/net/ipv4/ip_forward
  2. /sbin/iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE

Шаг 1 устанавливает параметр ядра, разрешающий переадресацию IP, шаг 2 устанавливает правило iptables, которое включает NAT на интерфейсе eth0.

Блокировать атаки ICMP

Добавьте следующие правила, желательно в -t raw -A PREROUTING

-p icmp -m u32 ! --u32 "4&0x3FFF=0"   -j DROP
-p icmp -m length --length 1492:65535 -j DROP

Первое правило блокирует все пакеты ICMP, чей «флаг фрагментации» не равен 0. (ICMP должен никогда быть фрагментированным; они должны нести небольшие полезные нагрузки)

Второе правило блокирует нефрагментированные ICMP-пакеты слишком большого размера.

(из моего файла iptables_tricks.txt, перекомпилированного из множества мест: P)

Заставляет iptables ждать 15 секунд между новыми подключениями с того же IP-адреса на порт 22 (SSH):

 iptables -A INPUT -p tcp -i eth0 -m state --state NEW --dport 22 -m recent --update --seconds 15 -j DROP
 iptables -A INPUT -p tcp -i eth0 -m state --state NEW --dport 22 -m recent --set -j ACCEPT

Снова о наборах IP

Уже есть ответ, в котором упоминаются наборы IP. Однако он довольно одномерен, поскольку фокусируется на выигрыше в производительности по сравнению с классическими правилами и на том факте, что наборы IP-адресов смягчают проблему с большим количеством отдельных IP-адресов, которые нельзя легко выразить как подсеть в нотации CIDR.

Обозначения, используемые ниже

Для ipset Я буду использовать обозначения, прочитанные ipset restore и написано ipset save.

Соответственно для iptablesip6tables) rules я буду использовать обозначения, как прочитал iptables-restore и написано iptables-save. Это сокращает нотацию и позволяет выделить потенциальные возможности использования только IPv4 (с префиксом -4) или только IPv6 (с префиксом -6) правила.

В некоторых примерах мы перенаправим поток пакетов в другую цепочку. Предполагается, что цепочка существует в этой точке, поэтому строки для создания цепочек не создаются (при этом не упоминается имя таблицы или команды COMMITв конце).

Расширенные наборы IP

Наборы IP могут намного больше, чем упоминалось в другой ответ и вам обязательно стоит прочитать документацию по IP-адресу (ipset(8)) вместе с iptables-extensions(8) в дополнение к этой краткой записи здесь.

Например, я в основном сосредоточусь на трех типах наборов: hash:ip, hash:net и list:set, но их гораздо больше, и все они имеют допустимые варианты использования.

Вы можете, например, также сопоставить номера портов, а не только IP-адреса.

Сохранение и восстановление наборов IP как с iptables-save и iptables-restore

Вы можете создавать объявления наборов IP-адресов в большом количестве и импортировать их, передавая их в ipset restore. Если вы хотите сделать свою команду более устойчивой к уже существующим записям, используйте ipset -exist restore.

Если ваши правила находятся в файле с именем default.set вы бы использовали:

ipset -exist restore < default.set

Такой файл может содержать записи для create наборы и add записи в них. Но, как правило, похоже, что для большинства команд из командной строки в файлах есть соответствующая версия. Пример (создание набора DNS-серверов):

create dns4 hash:ip family inet
create dns6 hash:ip family inet6
# Google DNS servers
add dns4 8.8.8.8
add dns4 8.8.4.4
add dns6 2001:4860:4860::8888
add dns6 2001:4860:4860::8844

Здесь создается один набор для IPv4 (dns4) и один для IPv6 (dns6).

Таймауты на наборах IP

Тайм-ауты в наборах IP-адресов можно установить по умолчанию для каждого набора, а также для каждой записи. Это очень полезно для сценариев, когда вы хотите временно заблокировать кого-либо (например, для сканирования портов или попытки перебора вашего SSH-сервера).

Это работает следующим образом (по умолчанию при создании наборов IP-адресов):

create ssh_loggedon4 hash:ip  family inet  timeout 5400
create ssh_loggedon6 hash:ip  family inet6 timeout 5400
create ssh_dynblock4 hash:ip  family inet  timeout 1800
create ssh_dynblock6 hash:ip  family inet6 timeout 1800

Мы вернемся к этим конкретным наборам ниже и объясним, почему они установлены именно так.

Если вы хотите установить время ожидания для определенного IP-адреса, вы можете просто сказать:

add ssh_dynblock4 1.2.3.4 timeout 7200

Чтобы заблокировать IP 1.2.3.4 на два часа вместо (установленных) полчаса по умолчанию.

Если бы вы посмотрели на это с помощью ipset save ssh_dynblock4 через короткое время вы увидите что-то вроде:

create ssh_dynblock4 hash:ip family inet hashsize 1024 maxelem 65536 timeout 1800
add ssh_dynblock4 1.2.3.4 timeout 6954

Предостережения относительно тайм-аута

  • таймауты - это особенность любого набора. Если бы набора не было создан с поддержкой тайм-аута вы получите сообщение об ошибке (например, Kernel error received: Unknown error -1).
  • таймауты указаны в секундах. Используйте арифметические выражения Bash, например, для перехода от минут к секундам. Например.: sudo ipset add ssh_dynblock4 1.2.3.4 timeout $((120*60))

Проверка наличия записи в данном наборе IP

Внутри ваших скриптов может быть полезно увидеть, существует ли уже запись. Этого можно достичь с помощью ipset test который возвращает ноль, если запись существует, и ненулевое значение в противном случае. Таким образом, в скрипте можно применять обычные проверки:

if ipset test dns4 8.8.8.8; then
  echo "Google DNS is in the set"
fi

Однако во многих случаях вы предпочтете использовать -exist переключиться на ipset чтобы направить его не жаловаться на существующие записи.

Заполнение наборов IP из iptables правила

Это, на мой взгляд, одна из главных черт IP-наборов. Вы можете не только сопоставить записи набора IP-адресов, но и добавить новые записи к существующему набору IP-адресов.

Например в этот ответ на этот вопрос у вас есть:

-A INPUT -p tcp -i eth0 -m state --state NEW --dport 22 -m recent --update --seconds 15 -j DROP
-A INPUT -p tcp -i eth0 -m state --state NEW --dport 22 -m recent --set -j ACCEPT

... с намерением ограничить количество попыток подключения к SSH (TCP-порт 22). Используемый модуль recent отслеживает недавние попытки подключения. Вместо state модуль, я предпочитаю conntrack модуль, однако.

# Say on your input chain of the filter table you have
   -A INPUT -i eth+ -p tcp --dport ssh -j SSH
# Then inside the SSH chain you can
# 1. create an entry in the recent list on new connections
   -A SSH -m conntrack --ctstate NEW -m recent --set --name tarpit
# 2. check whether 3 connection attempts were made within 2 minutes
#    and if so add or update an entry in the ssh_dynblock4 IP set
-4 -A SSH -m conntrack --ctstate NEW -m recent --rcheck --seconds 120 --hitcount 3 --name tarpit -j SET --add-set ssh_dynblock4 src --exist
-6 -A SSH -m conntrack --ctstate NEW -m recent --rcheck --seconds 120 --hitcount 3 --name tarpit -j SET --add-set ssh_dynblock6 src --exist
# 3. last but not least reject the packets if the source IP is in our
#    IP set
-4 -A SSH -m set --match-set ssh_dynblock4 src -j REJECT
-6 -A SSH -m set --match-set ssh_dynblock6 src -j REJECT

В этом случае я перенаправляю поток на SSH цепочка, чтобы мне не приходилось повторяться с -p tcp --dport ssh для каждого правила.

Чтобы повторить:

  • -m set делает iptables осознавая, что мы используем переключатели из set модуль (который обрабатывает наборы IP)
  • --match-set ssh_dynblock4 src говорит iptables чтобы соответствовать источник (src) адрес против именованного набора (ssh_dynblock4)
    • это соответствует sudo ipset test ssh_dynblock4 $IP (где $IP содержит исходный IP-адрес пакета)
  • -j SET --add-set ssh_dynblock4 src --exist добавляет или обновляет источник (src) адрес из пакета в набор IP ssh_dynblock4. Если запись существует (--exist) просто обновится.
    • это соответствует sudo ipset -exist add ssh_dynblock4 $IP (где $IP содержит исходный IP-адрес пакета)

Если вы хотите вместо этого сопоставить целевой / целевой адрес, вы должны использовать dst вместо того src. Обратитесь к руководству для получения дополнительных сведений.

Наборы наборов

Наборы IP могут содержать другие наборы. Теперь, если вы читали статью до этого места, вы задавались вопросом, можно ли комбинировать наборы. И конечно это так. Для указанных выше наборов IP мы можем создать два набора соединений ssh_dynblock и ssh_loggedon соответственно, чтобы содержать наборы только для IPv4 и только для IPv6:

create ssh_loggedon4 hash:ip  family inet  timeout 5400
create ssh_loggedon6 hash:ip  family inet6 timeout 5400
create ssh_dynblock4 hash:ip  family inet  timeout 1800
create ssh_dynblock6 hash:ip  family inet6 timeout 1800
# Sets of sets
create ssh_loggedon  list:set
create ssh_dynblock  list:set
# Populate the sets of sets
add ssh_loggedon ssh_loggedon4
add ssh_loggedon ssh_loggedon6
add ssh_dynblock ssh_dynblock4
add ssh_dynblock ssh_dynblock6

И следующий вопрос, который должен возникнуть у вас в голове: позволяет ли это нам соответствие и манипулировать наборами IP независимо от версии IP.

И ответ на это громкий: ДА! (увы, это не было явно задокументировано в прошлый раз, когда я проверял)

Следовательно, правила из предыдущего раздела можно переписать следующим образом:

-A INPUT -i eth+ -p tcp --dport ssh -j SSH
-A SSH -m conntrack --ctstate NEW -m recent --set --name tarpit
-A SSH -m conntrack --ctstate NEW -m recent --rcheck --seconds 120 --hitcount 3 --name tarpit -j SET --add-set ssh_dynblock src --exist
-A SSH -m set --match-set ssh_dynblock src -j REJECT

что намного короче. И да, это испытано и проверено и работает как шарм.

Собираем все вместе: защита от перебора SSH

На моих серверах у меня есть скрипт, запускаемый как cron задание, которое берет кучу имен хостов и преобразует их в IP-адреса, а затем передает их в набор IP для «доверенных хостов». Идея состоит в том, что доверенные хосты получают больше попыток входа на сервер и не обязательно блокируются на такое время, как кто-либо еще.

И наоборот, у меня целые страны заблокированы для подключения к моему SSH-серверу, за (потенциальным) исключением доверенных хостов (то есть порядок правил имеет значение).

Однако это оставлено читателю в качестве упражнения. Здесь я хотел бы добавить изящное решение, которое будет использовать наборы, содержащиеся в ssh_loggedon установлен, чтобы разрешить последующие попытки подключения и не подвергаться такой же проверке, как другие пакеты.

Важно помнить, что тайм-аут по умолчанию составляет 90 минут для ssh_loggedon и 30 минут для ssh_dynblock глядя на следующие iptables правила:

-A INPUT -i eth+ -p tcp --dport ssh -j SSH
-A SSH -m set --match-set ssh_loggedon src -j ACCEPT
-A SSH -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A SSH -m conntrack --ctstate NEW -m recent --set --name tarpit
-A SSH -m conntrack --ctstate NEW -m recent --rcheck --seconds 120 --hitcount 3 --name tarpit -j SET --add-set ssh_dynblock src --exist
-A SSH -m set --match-set ssh_dynblock src -j REJECT

К настоящему времени вы должны спросить себя, как подключаемый IP-адрес попадает в ssh_loggedon подмножества. Так что читайте дальше ...

Бонус: добавление IP-адреса, с которого вы входите во время входа в SSH

Если вы экспериментировали с sshrc и друзья, вы узнаете о его недостатках. Но на помощь приходит PAM. Модуль с именем pam_exec.so позволяет нам вызывать скрипт во время входа в систему по SSH в момент, когда мы знаем, что пользователь допущен.

В /etc/pam.d/sshd ниже pam_env и pam_selinux записи добавить следующую строку:

session    optional     pam_exec.so stdout /path/to/your/script

и убедитесь, что ваша версия скрипта (/path/to/your/script выше) существует и является исполняемым.

PAM использует переменные среды, чтобы сообщать о том, что происходит, поэтому вы можете использовать простой скрипт, подобный этому:

#!/bin/bash
# When called via pam_exec.so ...
SETNAME=ssh_loggedon
if [[ "$PAM_TYPE" == "open_session" ]] && [[ -n "$PAM_RHOST" ]]; then
    [[ "x$PAM_RHOST" != "x${PAM_RHOST//:/}" ]] && SETNAME="${SETNAME}6" || SETNAME="${SETNAME}4"
    ipset -exist add $SETNAME "$PAM_RHOST"
fi

К сожалению, ipset Утилита, похоже, не имеет встроенного интеллекта netfilter. Поэтому при добавлении нашей записи нам нужно различать IPv4 и IPv6. В противном случае ipset предположим, что мы хотим добавить еще один устанавливать к набору наборов вместо IP. И конечно вряд ли будет набор, названный по IP :)

Итак, мы проверяем : в IP-адресе и добавьте 6 к названию набора в таком случае и 4 в противном случае.

Конец.

с помощью FireHOL - удобная обертка iptables

Мне он показался более интуитивным, чем прямые команды iptables. Специально для людей, имеющих опыт работы с другими межсетевыми экранами:

FireHOL - это генератор брандмауэра iptables, создающий брандмауэры с фильтрацией пакетов iptables с отслеживанием состояния на хостах и ​​маршрутизаторах Linux с любым количеством сетевых интерфейсов, любым количеством маршрутов, любым количеством обслуживаемых сервисов, любым уровнем сложности между вариантами сервисов (включая положительные и отрицательные выражения).

Видеоуроки IPTABLES

Эпизод 1 http://www.youtube.com/watch?v=ldB8kDEtTZA&feature=player_embedded

Эпизод 2 http://www.youtube.com/watch?v=aDaEXxRHeXY&feature=related

Финальный эпизод

http://www.youtube.com/watch?v=JojqHKcSxpo&feature=player_embedded

Будет хорошим стартом для любого новичка.

Другой графический интерфейс, который можно использовать для настройки iptables: Конструктор межсетевого экрана. Он позволяет пользователям создавать элементы правил как объекты в базе данных, а затем перетаскивать эти объекты в редактор правил для создания желаемой политики брандмауэра. Затем приложение создает файл сценария со всеми командами iptables, необходимыми для реализации правил.

В отличие от некоторых других решений с графическим интерфейсом пользователя iptables, где вы можете управлять только одной конфигурацией iptables за раз, с Firewall Builder вы можете управлять большим количеством конфигураций iptables из одного приложения. Firewall Builder работает в Linux, Windows и Mac OS X, существует уже более 10 лет и имеет тысячи активных пользователей по всему миру.

Полное раскрытие информации - я соучредитель NetCitadel, компании, которая разрабатывает Firewall Builder.

Ограничение всех индивидуальных IP-адресов квотой исходящей полосы пропускания с помощью наборов IP

Вы можете настроить свой сервер так, чтобы каждый отдельный IP-адрес использовал 15 гигабайт полосы пропускания в месяц, в надежде отразить или избежать атаки на использование полосы пропускания, возможно, для вашей квоты измеренной полосы пропускания у вашего провайдера. Это может быть выполнено следующим образом:

Сначала создайте наборы IP для IPv4 и IPv6:

ipset create IP_QUOTA_SET_OUT hash:ip timeout 345600 counters
ipset create IP_QUOTA_SET_OUT_INET6 hash:ip timeout 345600 counters family inet6

Теперь добавьте свои правила iptables. Первая строка добавит IP-адрес в набор, если его еще нет. Вторая строка не будет соответствовать, если количество байтов, переданных для IP в наборе, превышает указанное количество. То же самое делается и для IPv6.

iptables -I OUTPUT -m set ! --match-set IP_QUOTA_SET_OUT dst -j SET --add-set IP_QUOTA_SET_OUT dst --timeout 345600
iptables -I OUTPUT -m set --match-set IP_QUOTA_SET_OUT dst --bytes-gt 16106127360 -j DROP

ip6tables -I OUTPUT -m set ! --match-set IP_QUOTA_SET_OUT_INET6 src -j SET --add-set IP_QUOTA_SET_OUT_INET6 src --timeout 345600
ip6tables -I OUTPUT -m set --match-set IP_QUOTA_SET_OUT_INET6 src --bytes-gt 16106127360 -j DROP

Это предотвратит такие атаки, как пользователь, запрашивающий большой файл с вашего веб-сервера в течение длительного периода времени или с любой службы, если на то пошло. То же самое можно сделать для цепочки INPUT.

Сопоставьте несколько имен интерфейсов с помощью подстановочного знака

Пример: у вас есть eth0 и eth1 и хотели бы разрешить трафик между ними?

iptables -A FORWARD -i eth+ -o eth+ -j ACCEPT

Я использовал это в прошлом, чтобы соответствовать veth<something> интерфейсы, динамически создаваемые и именуемые LXC. Так что я могу сопоставить все сразу с veth+.

Я также намеренно назвал некоторые интерфейсы _<something> чтобы противостоять _+.

регистрировать исходящее соединение с uid

iptables -A OUTPUT -m state --state NEW -m tcp -p tcp -m limit --limit 5/m -j LOG --log-uid --log-prefix="outgoing connection: "

переадресация порта / соединения:

iptables -A PREROUTING -t nat -i eth1 -p tcp --dport 80 -j DNAT --to 10.0.1.7:80
iptables -A INPUT -p tcp -m state --state NEW --dport 80 -i eth1 -j ACCEPT

Блокировать необычные значения MSS

iptables -t mangle -A PREROUTING -p tcp \
-m conntrack --ctstate NEW -m tcpmss ! --mss 536:65535 -j DROP

Цель SYNPROXY для защиты от DDos

Цель этой цели - проверить, устанавливает ли хост, отправивший SYN-пакет, соединение или ничего не делает после инициации SYN-соединения. Если он ничего не делает, он с минимальными усилиями отбрасывает пакет.

Установите пакеты синхронизации в таблицу отслеживания соединений в необработанной таблице

iptables -t raw -A PREROUTING -p tcp -m tcp --dport 80 --syn -j CT --notrack

Включите synproxy для http-сервера:

iptables -A INPUT -p tcp -m tcp --dport 80 -m conntrack --ctstate INVALID,UNTRACKED \
-j SYNPROXY --sack-perm --timestamp --wscale 7 --mss 1460

Ресурс: Цель SYNPROXY из блога RHEL

Что-то, что я делаю, в основном из-за моего незнания более элегантного решения, - это вручную проверять журналы Nginx каждые 4 часа, а журналы почтового сервера каждые 2 минуты на предмет чрезмерного доступа с отдельных IP-адресов. Я запускаю вместе несколько скриптов, которые:

  1. Проверить access.log и перечислите 10 лучших IP-адресов, упорядоченных по количеству обращений к серверу.
  2. Выгрузить результаты в файл журнала
  3. Попросите другой сценарий просмотреть этот файл журнала и заблокировать любой IP-адрес, который попадал на сервер более X раз за последние X часов.
  4. Спаси мой iptables.save

Вот как это выглядит:

autoBanIPs_mail.sh
#!/bin/bash

# This script checks the last 2 minutes of log entries to see if any 
# IP has made over 99 connections

now=$(date +"%m_%d_%Y")

/root/bin/checkBadIPs_mail.sh > /home/ipChecker/ipcheckMAIL_$now.txt
cat /home/ipChecker/ipcheckMAIL_$now.txt | \
    grep " \\(\\([9][9]\\)\\|\\([0-9][0-9][0-9]\\+\\)\\) " | \
    awk '{print $2}' > /home/ipChecker/badMailIPs_$now.sh
sed -i "s/^/\/usr\/local\/sbin\/blockIP /g" /home/ipChecker/badMailIPs_$now.sh
/bin/bash /home/ipChecker/badMailIPs_$now.sh
cat /home/ipChecker/ipcheckMAIL_$now.txt >> /home/ipChecker/ipcheckMAIL_$now.log
rm /home/ipChecker/ipcheckMAIL_$now.txt
rm /home/ipChecker/badMailIPs_$now.sh
checkBadIPs_mail.sh

Здесь ОЧЕНЬ важно отметить одну вещь: вам НЕОБХОДИМО настроить белый список, иначе вы собираетесь начать блокировать множество аутентичных IP-адресов с серверов, с которых вы просто получаете много электронной почты, или, в случае других журналов, IP-адреса, которые просто часто попадайте на ваш сервер по уважительным причинам. Мой белый список просто встроен в этот скрипт путем добавления каналов grep сразу после | grep ']' | это выглядит примерно так "grep -v 127.0 |".
Вам нужно потратить время, чтобы научить свой сервер, какие IP-адреса с высоким трафиком являются допустимыми, а какие - нет. Для меня это означало, что мне пришлось потратить первую неделю или около того, проверяя свои журналы вручную каждые пару часов, просматривая ip-адреса с высоким трафиком на iplocation.net, а затем добавляя легальные, такие как amazon, box.com или даже мой дом / офис. IP-адреса попадают в белый список. Если вы этого не сделаете, ваш собственный сервер, скорее всего, будет заблокирован, или вы начнете блокировать законные почтовые / веб-серверы и вызовете перебои в работе электронной почты или трафика.

cat /var/log/mail.log | awk \
    -v d1="$(date --date="-2 min" "+%b %_d %H:%M")" \
    -v d2="$(date "+%b %_d %H:%M")" \
    '$0 > d1 && $0 < d2 || $0 ~ d2' | \
    grep '\[' | grep '\]' | \
    grep -Eo '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' | grep -v 127.0 | \
    awk '{print $1}' | sort | uniq -c | sort -n | tail -10
BlockIP
#!/bin/bash
sudo iptables -I INPUT -s $1 -j DROP
sudo bash -c "iptables-save > /etc/network/iptables.save"

Опять же, я знаю, что это чертовски грубо, и, вероятно, есть хороший чистый и эффективный протокол, который делает все это, но я не знал об этом, и эта штука работает уже год или два и держит плохих парней в страхе. Единственное, что я очень СЕРЬЕЗНО рекомендую, - это наличие у вас прокси или другого сервера, который вы можете использовать для доступа к вашему основному серверу. Причина в том, что если вы однажды занимаетесь веб-разработкой совершенно неожиданно, и вы пингуйте себя 2000 раз за 5 часов для некоторого тестирования, вы могли быть заблокированы без возврата, кроме прокси.

Вы можете увидеть это в checkBadIPs.sh Я поместил grep -v 127.0, и в моих фактических файлах у меня есть тонна правил игнорирования для моего собственного IP-адреса и других доверенных диапазонов IP-адресов, но иногда ваш IP-адрес меняется, вы забываете обновить, а затем вы блокируете свой собственный сервер .

В любом случае, надеюсь, что это поможет.

ОБНОВИТЬ

Я немного изменил вещи, так что теперь вместо проверки каждые пару часов у меня есть журналы, проверяемые каждые 2 минуты, в основном мой журнал аутентификации ssh и журнал почты, когда они стучатся :(.

Я настраиваю определенные сценарии для каждого файла журнала, хотя это было бы достаточно просто из ручного сценария, который я использую сам, когда хочу проверить журналы. Выглядит так:

#!/bin/bash

log=$1 time=$2

cat /var/log/${log} | awk \
    -v d1="$(date --date="-${time} min" "+%b %_d %H:%M")" \
    -v d2="$(date "+%b %_d %H:%M")" \
    '$0 > d1 && $0 < d2 || $0 ~ d2' | \
    grep '\[' | grep '\]' | \
    grep -Eo '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' | \
    sort | uniq -c | sort -n | tail -10

Для этого требуется 2 входа при запуске: файл журнала, который вы хотите просканировать, и то, как далеко в прошлом вы хотите сканировать.

Итак, если бы я хотел проверить mail.log на счетчик IP, скажем, 75 минут назад, я бы запустил:

$ sudo script.sh mail.log 75

Я согласен с комментариями о флагах ipsets и tcp, но по-прежнему многого не хватает:

Для списков стран используйте xtables-addons geoip match вместо ipsets. Регулярно обновляйте данные geoip (не реже одного раза в месяц). Данные более динамичны, чем список ipset, который запускается и забывается.

Рассмотрим отслеживание состояния соединения с помощью tcp-флагов. Например, tcp RST или ACK имеет смысл только для установленного соединения. SYN имеет смысл только для новых и связанных соединений. SYN для установленного соединения означает, что либо ваш SYN + ACK был утерян, либо попытка взлома, и его следует сбросить, поскольку обе стороны соединения не согласны с утверждением.

Хотя нет, SYN + RST и FIN + RST являются недопустимыми комбинациями, SYN + FIN теперь действителен для TCP fast-open (TCP option 34), особенно для DNS. Пакеты SYN, даже с быстрым открытием, не должны фрагментироваться. Я не считаю правила с флагами PSH и URG полезными. Не путайте состояние отслеживания соединения с состоянием TCP: RST-ответ на SYN-пакет устанавливается для целей отслеживания.

SYNPROXY предназначен для пересылаемых пакетов и ничего не добавляет для локально доставленных, кроме поддержки syncookie.

Пакеты ошибок ICMP всегда будут в соответствующем состоянии и имеют длину 48: 576, если они действительны. Длина 84: 1280 для IPv6. Все остальные следует игнорировать. Поскольку их максимальный размер также является минимальным MTU, их нельзя фрагментировать. Запросы ICMP (эхо-запросы, отметки времени и т. Д.) Всегда будут новыми, а ответы установлены. Отбрасывать пакеты ICMP в других состояниях.

Подобно примеру SSH с последним списком и приемом только последующих пакетов SYN, то же самое следует сделать для SMTP и аналогично «серому списку» только для данных IP-адреса.

В таблице фильтров первое (или второе, если сначала принимает пакеты с установленным состоянием) правило во входных и выходных цепочках должно принимать все на интерфейсе обратной связи. Вы должны доверять своим собственным внутренним пакетам. Если вы не можете, у вас есть более серьезные проблемы, помимо решения брандмауэра.

Наконец, не копируйте правила вслепую, если вы действительно не понимаете, что они делают. Так поступает так много похожих списков правил, и в большинстве случаев результат смехотворен.

#!/bin/bash
# The following iptables/ip6tables configurations have
# been kindly shared with us from ArckWiki. There are
# a few additions apart from what has been defined.
#
#=================Flush current definitions==============
    iptables -F
    ip6tables -F
    iptables -X
    ip6tables -X

#
#=================Chains=================================
#
#----Define chains for opened ports
    iptables -N TCP
    ip6tables -N TCP
    iptables -N UDP
    ip6tables -N UDP

#
#----Setting up the filter table for NAT
#   iptables -N fw-interfaces
#   ip6tables -N fw-interfaces
#   iptables -N fw-open
#   ip6tables -N fw-open

#
#================Default Chain reactions=================
#
#----Default FORWARD reaction
    iptables -P FORWARD DROP
    ip6tables -P FORWARD DROP

#
#----Default OUTPUT reaction
    iptables -P OUTPUT ACCEPT
    ip6tables -P OUTPUT ACCEPT

#
#----Shellshock
    iptables -A INPUT -m string --algo bm --hex-string '|28 29 20 7B|' -j DROP
    ip6tables -A INPUT -m string --algo bm --hex-string '|28 29 20 7B|' -j DROP

#
#----Default INPUT reaction
    iptables -P INPUT DROP
    ip6tables -P INPUT DROP
#
#----Drop spoofing packets
    iptables -A INPUT -i eth0 -s 127.0.0.0/8 -j DROP
    iptables -A INPUT -i wlan0 -s 127.0.0.0/8 -j DROP
    iptables -A INPUT -i wlan1 -s 127.0.0.0/8 -j DROP
    iptables -A INPUT -s 10.0.0.0/8 -j DROP
    iptables -A INPUT -s 169.254.0.0/16 -j DROP
    iptables -A INPUT -s 172.16.0.0/12 -j DROP
    iptables -A INPUT -s 224.0.0.0/4 -j DROP
    iptables -A INPUT -d 224.0.0.0/4 -j DROP
    iptables -A INPUT -s 240.0.0.0/5 -j DROP
    iptables -A INPUT -d 240.0.0.0/5 -j DROP
    iptables -A INPUT -s 0.0.0.0/8 -j DROP
    iptables -A INPUT -d 0.0.0.0/8 -j DROP
    iptables -A INPUT -d 239.255.255.0/24 -j DROP
    iptables -A INPUT -d 255.255.255.255 -j DROP

#
#================Ping rate limiting globally=============
    iptables -A INPUT -p icmp --icmp-type 8 -m limit --limit 30/min --limit-burst 8 -j ACCEPT
    ip6tables -A INPUT -p icmpv6 --icmpv6-type 8 --match limit --limit-burst 8 -j ACCEPT
    iptables -A INPUT -p icmp --icmp-type 8 -j DROP
    ip6tables -A INPUT -p icmpv6 --icmpv6-type 8 -j DROP

#
#----flooding RST packets, smurf attack Rejection
    iptables -A INPUT -p tcp -m tcp --tcp-flags RST RST -m limit --limit 2/second --limit-burst 2 -j ACCEPT
    ip6tables -A INPUT -p tcp -m tcp --tcp-flags RST RST -m limit --limit 2/second --limit-burst 2 -j ACCEPT

#
#----Bogus packet DROP
    iptables -A INPUT -p tcp -m tcp --tcp-flags SYN,FIN SYN,FIN -j DROP
    ip6tables -A INPUT -p tcp -m tcp --tcp-flags SYN,FIN SYN,FIN -j DROP
    iptables -A INPUT -p tcp -m tcp --tcp-flags SYN,RST SYN,RST -j DROP
    ip6tables -A INPUT -p tcp -m tcp --tcp-flags SYN,RST SYN,RST -j DROP

#
#================RELATED,ESTABLISHED reaction============
    iptables -A INPUT --match conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
    ip6tables -A INPUT --match conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT

#
#================unfetered loopback======================
    iptables -A INPUT -i lo -j ACCEPT
    ip6tables -A INPUT -i lo -j ACCEPT

#
#================INVALID catagory of packets=============
    iptables -A INPUT -p 41 -j ACCEPT
    iptables -A INPUT --match conntrack --ctstate INVALID -j DROP
    ip6tables -A INPUT --match conntrack --ctstate INVALID -j DROP

#
#================IPv6 reactions and definitions==========
    ip6tables -A INPUT -s fe80::/10 -p icmpv6 -j ACCEPT
    ip6tables -t raw -A PREROUTING -p icmpv6 -s fe80::/10 -j ACCEPT
    ip6tables -t raw -A PREROUTING --match rpfilter -j ACCEPT
    ip6tables -t raw -A PREROUTING -j DROP
#
#=======Acceptable INVALIDs and a curteous response======
    iptables -A INPUT -p udp --match conntrack --ctstate NEW -j UDP
    ip6tables -A INPUT -p udp --match conntrack --ctstate NEW -j UDP
    iptables -A INPUT -p tcp --syn --match conntrack --ctstate NEW -j TCP
    ip6tables -A INPUT -p tcp --syn --match conntrack --ctstate NEW -j TCP

#
#================Defining the TCP and UDP chains
#
#########################################################
#            Notes for port open definitions            #
# It is important to note that this should be config-   #
# ured differently if you're providing any routing      #
# activity for any purpose. it is up to you to actively #
# define what suites your needs to get the job done.    #
# In this example, I'm exempting IPv6 from being able   #
# to interact with SSH protocols for two reasons. The   #
# first is because it is generally easier and more com- #
# for internal networks to be deployed with IPv4. The   #
# second reason is, IPv6 can be deployed globally.      #
#########################################################
#
#----SSH configured for eth0
    iptables -A TCP -i eth0 -p tcp --dport ssh -j ACCEPT

#!---Blocking SSH interactions in IPv6
    ip6tables -A TCP -p tcp --dport ssh -j DROP

#!---Leave commented for end service device
#   iptables -A TCP -p tcp --dport 80 -j ACCEPT
#   ip6tables -A TCP -p tcp --dport 80 -j ACCEPT
#   iptables -A TCP -p tcp --dport 443 -j ACCEPT
#   ip6tables -A TCP -p tcp --dport 443 -j ACCEPT
#
#!---Uncomment for remote service to this device
#   iptables -A TCP -p tcp --dport 22 -j ACCEPT
#   ip6tables -A TCP -p tcp --dport 22 -j ACCEPT
#
#!---Uncomment if you're providing routing services
#   iptables -A UDP -p udp 53 -j ACCEPT
#   ip6tables -A UDP -p udp 53 -j ACCEPT
#
#=================Tricking port scanners=================
#
#----SYN scans
    iptables -I TCP -p tcp --match recent --update --seconds 60 --name TCP-PORTSCAN -j DROP
    ip6tables -I TCP -p tcp --match recent --update --seconds 60 --name TCP-PORTSCAN -j DROP
    iptables -A INPUT -p tcp --match recent --set --name TCP-PORTSCAN -j DROP
    ip6tables -A INPUT -p tcp --match recent --set --name TCP-PORTSCAN -j DROP

#
#----UDP scans
    iptables -I UDP -p udp --match recent --update --seconds 60 --name UDP-PORTSCAN -j DROP
    ip6tables -I UDP -p udp --match recent --update --seconds 60 --name UDP-PORTSCAN -j DROP
    iptables -A INPUT -p udp --match recent --set --name UDP-PORTSCAN -j DROP
    ip6tables -A INPUT -p udp --match recent --set --name UDP-PORTSCAN -j DROP

#
#----For SMURF attack protection
    iptables -A INPUT -p icmp -m icmp --icmp-type address-mask-request -j DROP
    iptables -A INPUT -p icmp -m icmp --icmp-type timestamp-request -j DROP
    iptables -A INPUT -p icmp -m limit --limit 2/second --limit-burst 2 -j ACCEPT
    ip6tables -A INPUT -p icmpv6 -m limit --limit 2/second --limit-burst 2 -j ACCEPT

#
#----Ending all other undefined connections
    iptables -A INPUT -j DROP
    ip6tables -A INPUT -j DROP

#
#=======Defining the IN_SSH chain for bruteforce of SSH==
#
#!---I've elected to keep IPv6 out of this realm for
#!---ease of use
    iptables -N IN_SSH
    iptables -A INPUT -p tcp --dport ssh --match conntrack --ctstate NEW -j IN_SSH
    iptables -A IN_SSH --match recent --name sshbf --rttl --rcheck --hitcount 3 --seconds 10 -j DROP
    iptables -A IN_SSH --match recent --name sshbf --rttl --rcheck --hitcount 4 --seconds 1800 -j DROP
    iptables -A IN_SSH --match recent --name sshbf --set -j ACCEPT
    iptables -A INPUT -p tcp --dport ssh -m conntrack --ctstate NEW -j IN_SSH

#
#==================Setting up a NAT gateway==============
#
#########################################################
#                                                       #
# I commented this half out because it's not something  #
# that will apply to all setups. Make note of all par-  #
# tinate interfaces and what exactly is going on.       #
#                                                       #
#########################################################
#
#----Setting up the FORWARD chain
#   iptables -A FORWARD --match conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
#   ip6tables -A FORWARD --match conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
#
#
#----Defining the fw-interfaces/open chains for FORWARD
#   iptables -A FORWARD -j fw-interfaces
#   ip6tables -A FORWARD -j fw-interfaces
#   iptables -A FORWARD -j fw-open
#   ip6tables -A FORWARD -j fw-open
#   iptables -A FORWARD -j DROP # Should be REJECT. But, fuck them
#   ip6tables -A FORWARD -j DROP
#   iptables -P FORWARD DROP
#   ip6tables -P FORWARD DROP
#
#
#----Setting up the nat table
#   iptables -A fw-interfaces -i ### -j ACCEPT
#   ip6tables -A fw-interfaces -i ### -j ACCEPT
#   iptables -t nat -A POSTROUTING -s w.x.y.z/S -o ppp0 -j MASQUERADE
#   ip6tables -t nat -A POSTROUTING -s fe::/10 -o ppp0 -j MASQUERADE
#----The above lines should be repeated specifically for EACH interface
#
#----Setting up the PREROUTING chain
#
#######################################################
#                             #
# The PREROUTING chain will redirect either port      #
# targets to be redirected. This can also redirect    #
# traffic inbound to your network from the gateway    #
# to this machine. This can be useful if you're using #
# a honeypot or have any service within your network  #
# that you want to be pointed to a specific device.   #
#                             #
#######################################################
#
#----SSH honeypot server
#   iptables -A fw-open -d HONEYPOT_IP -p tcp --dport 22 -j ACCEPT
#   ip6tables -A fw-open -d HONEYPOT_IP -p tcp --dport 22 -j ACCEPT
#----With intuition, you can configure the above to also direct specific
#----requests to other devices providing those services. The bellow will
#----be for a squid server
#   iptables -A fw-open -d SQUID_IP -p tcp --dport 80 -j ACCEPT
#   ip6tables -A fw-open -d SQUID_IP -p tcp --dport 80 -j ACCEPT
#   iptables -t nat -A PREROUTING -i ppp0 -p tcp --dport 8000 -j DNAT --to SQUID_IP
#   ip6tables -t nat -A PREROUTING -i ppp0 -p tcp --dport 8000 -j DNAT --to SQUID_IP
#
#===============Declare configurations=================
    iptables -nvL
    ip6tables -nvL