Всем привет!
Я пытаюсь настроить брандмауэр своего сервера с помощью iptables (должен признать, что последний раз я использовал iptables год назад), но iptables действует вопреки тому, о чем я прошу.
Вот мой тестовый сценарий:
#!/bin/sh
IPT="/sbin/iptables"
echo -n "Loading iptables rules..."
# Flush old rules
$IPT --flush
$IPT --delete-chain
# Allow incoming and outgoing for loopback interfaces
$IPT -A INPUT -i lo -j ACCEPT
$IPT -A OUTPUT -o lo -j ACCEPT
# Allow incoming traffic for HTTP(S), SSH and SMTP
$IPT -A INPUT -p tcp --dport 80 -i eth0 -j ACCEPT
$IPT -A INPUT -p tcp --dport 443 -i eth0 -j ACCEPT
$IPT -A INPUT -p tcp --dport 22 -j ACCEPT
$IPT -A INPUT -p tcp --dport 25 -i eth0 -j ACCEPT
# Allow ICMP requests
$IPT -A INPUT -p icmp -i eth0 -j ACCEPT
$IPT -A OUTPUT -p icmp -o eth0 -j ACCEPT
# Allow outgoing traffic for SMTP, DNS, NTP, PgSQL, SolR, and SSH
$IPT -A OUTPUT -p tcp --dport 25 -o eth0 -j ACCEPT
$IPT -A OUTPUT -p tcp --dport 53 -o eth0 -j ACCEPT
$IPT -A OUTPUT -p udp --dport 53 -o eth0 -j ACCEPT
$IPT -A OUTPUT -p udp --dport 123 -o eth0 -j ACCEPT
$IPT -A OUTPUT -p tcp --dport 5433 -o eth0.2654 -j ACCEPT
$IPT -A OUTPUT -p udp --dport 5433 -o eth0.2654 -j ACCEPT
$IPT -A OUTPUT -p tcp --dport 8983 -o eth0.2654 -j ACCEPT
$IPT -A OUTPUT -p udp --dport 8983 -o eth0.2654 -j ACCEPT
$IPT -A OUTPUT -p tcp --dport 22 -o eth0 -j ACCEPT
$IPT -A OUTPUT -p tcp --dport 22 -o eth0.2654 -j ACCEPT
# Deny web server user outgoing connections
$IPT -A OUTPUT -o eth0 -m owner --uid-owner www-data -j DROP
# Drop everything else
$IPT -A INPUT -j DROP
$IPT -A OUTPUT -j DROP
$IPT -A FORWARD -j DROP
echo "rules loaded."
# Print rules as understood, then flush to avoid lockout
sleep 10
$IPT -L
# Flush old rules
$IPT --flush
$IPT --delete-chain
С помощью этого сценария сервер больше не отвечает ни на один запрос, кроме ping (ICMP), затем, через 10 секунд, печатает следующий текст и завершает работу:
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
100 5920 ACCEPT all -- lo any anywhere anywhere
0 0 ACCEPT tcp -- eth0 any anywhere anywhere tcp dpt:www
0 0 ACCEPT tcp -- eth0 any anywhere anywhere tcp dpt:https
1 52 ACCEPT tcp -- any any anywhere anywhere tcp dpt:ssh
0 0 ACCEPT tcp -- eth0 any anywhere anywhere tcp dpt:smtp
0 0 ACCEPT icmp -- eth0 any anywhere anywhere
0 0 DROP all -- any any anywhere anywhere
Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
0 0 DROP all -- any any anywhere anywhere
Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
100 5920 ACCEPT all -- any lo anywhere anywhere
0 0 ACCEPT icmp -- any eth0 anywhere anywhere
0 0 ACCEPT tcp -- any eth0 anywhere anywhere tcp dpt:smtp
0 0 ACCEPT tcp -- any eth0 anywhere anywhere tcp dpt:domain
0 0 ACCEPT udp -- any eth0 anywhere anywhere udp dpt:domain
0 0 ACCEPT udp -- any eth0 anywhere anywhere udp dpt:ntp
0 0 ACCEPT tcp -- any eth0.2654 anywhere anywhere tcp dpt:5433
0 0 ACCEPT udp -- any eth0.2654 anywhere anywhere udp dpt:5433
0 0 ACCEPT tcp -- any eth0.2654 anywhere anywhere tcp dpt:8983
0 0 ACCEPT udp -- any eth0.2654 anywhere anywhere udp dpt:8983
0 0 ACCEPT tcp -- any eth0 anywhere anywhere tcp dpt:ssh
0 0 ACCEPT tcp -- any eth0.2654 anywhere anywhere tcp dpt:ssh
0 0 DROP all -- any eth0 anywhere anywhere owner UID match www-data
14 2061 DROP all -- any any anywhere anywhere
Первый беспокоящий элемент, я заметил, что первые правила INPUT и OUTPUT - ПРИНЯТЬ все пакеты, тогда как я не просил об этом. Кроме того, я попытался установить политику INPUT и OUTPUT на DROP (используя $IPT -P INPUT DROP
и $IPT -P OUTPUT DROP
), но это окончательно заблокировало меня, даже после десятисекундного тайм-аута, и сервер тогда отвечает только на ICMP, что заставляет меня жестко перезагружать сервер. Тот же эффект, если я установил параметры политики в начале скрипта.
Я подозреваю, что моя ошибка очевидна для обычных пользователей iptables, но я искал решение в течение нескольких часов, и, как всегда в подобных ситуациях, ответ будет очевиден для меня только тогда, когда кто-то укажет на это. Пожалуйста, кто-нибудь из добрых дел мне поможет?
eth0.2654
VLAN, используемая для связи с нашим сервером PgSQL. Что касается ответов HTTP, у меня сложилось впечатление, что они используют соединение, открытое клиентом, что разрешено моим правилом. Я был неправ?
Что касается ответов HTTP, у меня создалось впечатление, что они используют соединение, открытое клиентом, что разрешено моим правилом. Я был неправ?
Да, вы ошибались. Скорее всего, вы захотите принять установленные соединения или связанные с входящими соединениями. Таким образом, можно ответить на все, что принято в правиле ввода. При использовании брандмауэра без сохранения состояния нужно явно открывать исходный порт. Поскольку IPtables отслеживает состояние, вам не нужно этого делать. Он будет отслеживать состояние подключений для вас и автоматически разрешать исходящие подключения, как вы думаете, но только если вы скажете ему об этом. Правило для этого iptables -A INPUT -p ALL -m state --state ESTABLISHED,RELATED -j ACCEPT
. Поместите это в начало вашего выходного списка. Если вы хотите быть особенно агрессивным, вы можете привязать это правило к определенным портам.
Если бы вы смотрели на это без сохранения состояния, вам нужно было бы помнить, откуда приходят и куда идут пакеты. В настоящее время ваш сервер настроен, чтобы вы могли подключаться к другому компьютеру по SSH. Поскольку вы не разрешаете трафик с портом 22 в качестве источника, ваш сервер не может отвечать на входящие соединения. Опять же, правило «ESTABLISHED, RELATED» решает эту проблему, разрешая трафику отвечать на входящие соединения, как и разрешая трафик, исходящий из порта 22, но в отличие от открытия 22 на межсетевом экране без сохранения состояния, эта настройка не позволяет запускать новые соединения оттуда.
Ваш подход плохой. Вы разрешаете все входные соединения, а затем останавливаете их на выходе. Это не предотвратит DDoS-атаки. Правильный способ - остановить входные соединения и разрешить выход.
Читая ваш код, я пытался переделать. Вот как, я думаю, это должно выглядеть:
#!/bin/sh
IPT=/usr/sbin/iptables
echo "Clear firewall rules..."
$IPT -F
$IPT -Z
$IPT -t nat -F
$IPT -t nat -Z
$IPT -t mangle -F
$IPT -t mangle -Z
$IPT -X
echo "Setting firewall policy..."
$IPT -P INPUT DROP # Deny all incoming connections
$IPT -P OUTPUT ACCEPT # Allow all outgoing connections
$IPT -P FORWARD DROP # Deny all forwaring
echo "Allow connections from: lo, eth0, eth0.2654"
$IPT -I INPUT -i lo -j ACCEPT
$IPT -I INPUT -i eth0 -j ACCEPT
echo "Allow icmp requests from eth0"
$IPT -A INPUT -p icmp -i eth0 -j ACCEPT
echo "Allow traffic for HTTP(S), SSH, SMTP, DNS, NTP, PgSQL, SolR"
$IPT -A INPUT -p tcp --dport 22 -j ACCEPT
$IPT -A INPUT -p tcp --dport 25 -i eth0 -j ACCEPT
$IPT -A INPUT -p tcp --dport 53 -i eth0 -j ACCEPT
$IPT -A INPUT -p udp --dport 53 -i eth0 -j ACCEPT
$IPT -A INPUT -p tcp --dport 80 -i eth0 -j ACCEPT
$IPT -A INPUT -p udp --dport 123 -i eth0 -j ACCEPT
$IPT -A INPUT -p tcp --dport 443 -i eth0 -j ACCEPT
$IPT -A INPUT -p tcp --dport 5433 -i eth0.2654 -j ACCEPT
$IPT -A INPUT -p udp --dport 5433 -i eth0.2654 -j ACCEPT
$IPT -A INPUT -p tcp --dport 8983 -i eth0.2654 -j ACCEPT
$IPT -A INPUT -p udp --dport 8983 -i eth0.2654 -j ACCEPT
echo "Deny web server user outgoing connections; eth0"
$IPT -A INPUT -o eth0 -m owner --uid-owner www-data -j DROP
echo "Drop everything."
$IPT -A INPUT -s 0/0 -j DROP
echo "Firewall loaded."
sleep 20
$IPT -nvL
echo "Clear firewall rules..."
$IPT -F
$IPT -Z
$IPT -t nat -F
$IPT -t nat -Z
$IPT -t mangle -F
$IPT -t mangle -Z
$IPT -X
Я не тестировал, так что имейте это в виду. Я не уверен, что "-i eth0.2654" будет работать с виртуальными интерфейсами.
Если хотите - попробуйте и дайте мне знать, работает он или нет.