Вопрос или проблема
Основные правила:
OUTIF=eth0
/sbin/iptables --policy INPUT DROP
/sbin/iptables --policy FORWARD DROP
/sbin/iptables --policy OUTPUT ACCEPT
/sbin/iptables -A INPUT -i lo -j ACCEPT
/sbin/iptables -A INPUT -i $OUTIF -m state --state RELATED,ESTABLISHED -j ACCEPT
Я хочу, чтобы MySQL слушал на lo
на порту 3306. И я также хочу, чтобы он слушал на порту 33060 на WAN интерфейсе (eth0
), так как хочу держать его подальше от ботов.
Я пробовал несколько перенаправлений без успеха. Например:
/sbin/iptables -A INPUT -p tcp -i $OUTIF --dport 34306 -j ACCEPT
/sbin/iptables -A PREROUTING -t nat -p tcp -s 0/0 --dport 34306 \
-j DNAT --to 127.0.0.1:3306
Как мне это сделать?
ИСПРАВЛЕНО:
Я собираюсь использовать redir, однако я все еще хочу знать, как сделать это с помощью iptables.
Это может сработать, но только если вы разрешите доступ к порту 3306 снаружи: (но это не работает)
iptables -t nat -A PREROUTING -p tcp --dport 34306 --syn -j DNAT --to :3306
Тем не менее, в конечном итоге вы хотите сделать следующее: (но это тоже не работает)
iptables -t nat -A PREROUTING -p tcp --dport 34306 --syn -j DNAT --to 127.0.0.1:3306
То есть вы хотите, чтобы пакеты на порт 34306 на внешнем интерфейсе перенаправлялись на 127.0.0.1, порт 3306. И это будет работать, если бы не тот факт, что, как только адрес назначения переписывается на 127.0.0.1, пакет становится марсианским пакетом (приходящим снаружи с адресом назначения 127.0.0.1). Марсианские пакеты обычно фильтруются молча, и вы действительно, действительно хотите, чтобы это произошло.
Существует более обходное решение с использованием меток файрволла. Теория: когда пакет приходит на порт 34306/tcp на вашем внешнем интерфейсе, мы просто помечаем его как допустимый, затем переписываем адрес так, чтобы он казался приходящим с 3306/tcp. Трафик к 3306/tcp с меткой разрешен. Весь другой трафик к 3306/tcp отклоняется (либо явно, либо неявно, через политику по умолчанию). Код:
IFACE=eth0 # или какой-либо другой
HIPORT=34306
REALPORT=3306
MARK=42 # не очень случайное случайное число
iptables -t mangle -A PREROUTING -p tcp -i $IFACE --dport $HIPORT -j MARK --set-mark $MARK
iptables -t nat -A PREROUTING -p tcp --dport $HIPORT --syn -j DNAT --to :$REALPORT
iptables -A INPUT -p tcp -m mark --mark $MARK -j ACCEPT
iptables -A INPUT -p tcp --dport $REALPORT -j DROP # явно отклоняем
Последнее правило — это то место, где вы можете стремиться к действию на недопустимых пакетах. Мне нравится регистрировать все отклоненные пакеты, так что мои цепи переходят к последним двум правилам, которые являются -j LOG
и -j DROP
. Так что в моем случае мне это не нужно, но ваше собственное время, конечно, может варьироваться.
Я только что протестировал это, и это работает в моей конфигурации. Это немного более сложный путь, чем ожидалось, но такая жизнь с netfilter.
Если вы используете состояние потоков, добавьте --syn
к правилу 3 (-m mark
в цепочке INPUT
) и поместите его перед правилами проверки состояния. Если вы явно отклоняете/отказываете пакеты с помощью правила 4 и делаете фильтрацию по состоянию, вам также следует добавить --syn
к этому. Это немного более сложно (на восемь полных байт), но правила проверки меток применяются только к SYN (первому) пакету каждого TCP-соединения. Как только решение о приеме/отказе было принято, правила проверки состояния делают остальное, поэтому файрвол не должен продолжать проверять метки для каждого отдельного пакета. Нет причин тратить циклы ЦП, и это поддерживает высокую производительность вашей сети.
Некоторые вещи, о которых стоит помнить:
- Ваш вопрос упоминает порт 33060, но ваш код использует порт 34306. Я использовал последний.
- Убедитесь, что MySQL действительно слушает на 127.0.0.1:3306. Он может использовать сокет UNIX для локальных коммуникаций, а не сокет интернет-домена (TCP/IP), и это не сетевое.
- Вам нужно только
DNAT
пакетSYN
. Состояние NAT автоматически переведет все остальные пакеты. Это немного ускоряет процесс. - Вам не нужно явно указывать -s 0/0, просто оставьте источник полностью пустым.
Суть вопроса: безопасность путем сокрытия — это жесткая госпожа. Вы на самом деле не защищаете себя, изменяя порт, на котором слушает MySQL. Сканеры портов — это автоматизированные вещи, и им не мешает сканировать все порты на системе. 🙂 Я рекомендую использовать ssh
с опцией -L
для безопасного туннелирования, или, если вы хотите усложнить, VPN. Но иногда жизнь дает вам лимоны, и вам нужно сделать лимонный сок с помощью netfilter (что, вероятно, одно из немногих вещей, которые вы не можете сделать с ним)
Теперь в 2024 году это все намного проще.
Просто включите маршрутизацию локальных пакетов:
sysctl -w net.ipv4.conf.all.route_localnet=1
и выполните простое DNAT:
iptables -t nat -A PREROUTING -p tcp -m addrtype --dst-type LOCAL --dport 33060 -j DNAT --to 127.0.0.1:3306
Просто будьте осторожны, чтобы использовать -m addrtype --dst-type LOCAL
, как показано выше. В противном случае перенаправленные соединения на порт 33060 других хостов (например, если ваш сервер подключает несколько сетей) также будут попадать на ваш локальный сервер базы данных.
Просто взгляните на инструменты, такие как nmap, учитывая, что злодеи, управляющие ботнетами, имеют неограниченное время и машины, и оцените, сколько времени “скрытие MySQL на (легко угадываемом) порту” купит вам.
Ответ или решение
Перенаправление порта с помощью iptables для MySQL
Если вы хотите перенаправить порт с loopback-устройства на внешний интерфейс с использованием iptables, чтобы MySQL слушал на локальном хосте по порту 3306 и на внешнем интерфейсе (например, eth0) по порту 33060, вам необходимо учесть несколько факторов, чтобы избежать фильтрации так называемых "марсианских пакетов".
Основные правила iptables
На основе вашего исходного запроса, у вас уже установлены следующие политики:
OUTIF=eth0
/sbin/iptables --policy INPUT DROP
/sbin/iptables --policy FORWARD DROP
/sbin/iptables --policy OUTPUT ACCEPT
/sbin/iptables -A INPUT -i lo -j ACCEPT
/sbin/iptables -A INPUT -i $OUTIF -m state --state RELATED,ESTABLISHED -j ACCEPT
Это означает, что входящий трафик по умолчанию отклоняется, кроме как для отLoopback-устройства (lo
) и установленных соединений.
Перенаправление портов
Для перенаправления порта 33060 на порт 3306 на локальном хосте с помощью iptables, вы можете использовать следующий набор команд:
-
Включение маршрутизации пакетов локально:
sysctl -w net.ipv4.conf.all.route_localnet=1
-
Использование правил iptables для перенаправления:
iptables -t nat -A PREROUTING -p tcp -m addrtype --dst-type LOCAL --dport 33060 -j DNAT --to 127.0.0.1:3306
Это правило позволит перенаправлять пакеты, приходящие на порт 33060 на вашем интерфейсе eth0, на порт 3306 на loopback-устройстве.
Проверка работы MySQL
Убедитесь, что MySQL слушает по адресу 127.0.0.1 на порту 3306. Это можно проверить с помощью команды:
netstat -tuln | grep 3306
Важные моменты
- Использование флага
-m addrtype --dst-type LOCAL
критически важно, чтобы предотвратить случайное перенаправление трафика к другим хостам или на другие интерфейсы. - Обязательно перезапустите iptables или примените изменения, чтобы убедиться, что они работают корректно.
Дополнительные рекомендации
Рекомендуется всегда использовать дополнительные меры безопасности, такие как:
- VPN: для защищенного доступа к вашей базе данных.
- SSH Tunnel: как простой способ туннелирования к базам данных.
Не полагайтесь исключительно на изменение портов как на средство защиты. Используйте многоуровневый подход к безопасности, чтобы минимизировать риски.
Заключение
Перенаправление портов с использованием iptables требует внимательности к деталям и правильной конфигурации сетевых правил. Вышеуказанные команды и рекомендации помогут вам достигнуть желаемого результата, обеспечивая безопасность вашего MySQL-сервера.