Защита от спама sendmailЧерез месяц после настройки почтового сервера на приём почты из интернета для собственного домена я обнаружил, что на мой почтовый ящик стало приходить довольно много спама. 2-3 письма со спамом в день я уже считаю много.
В этой статье я покажу что можно предпринять для борьбы со спамом на собственном сервере.

Вся настройка будет относится к дистрибутиву Fedora. На момент написания статьи это была Fedora-16.
Это всё относится так же и к дистрибутиву Centos 6.
В других дистрибутивах смотрите версию sendmail. Она должна быть не менее 8.14.3.
В более старых Centos’ах, в 5.7 например, sendmail версии только 8.13.

Удаление почтовых ящиков системных пользователей

Первым этапом я отключил все служебные почтовые ящики, на которые приходило множество писем со спамом.
Это те ящики имена которых совпадают с логинами служебных утилит.

Добавляем в файл /etc/mail/access строки

To:info@feser.ru 550 We do not accept mail from spammers
To:adm@feser.ru 550 We do not accept mail from spammers
To:admin@feser.ru 550 We do not accept mail from spammers
To:mail@feser.ru 550 We do not accept mail from spammers
To:sales@feser.ru 550 We do not accept mail from spammers

Необходимо помнить, что ящик postmaster отключать нельзя. Хотя на него и приходит спам, тем не менее вся служебная информация о невозможности доставить письмо куда важнее, да и письма со спамом на этот адрес приходят очень редко (раз в 2-3 месяца).

Защита от слишком частых соединений

Вторым этапом я попытался ограничить чересчур частые соединения спам-ботов на smtp порт.
Вот часть скрипта, который у меня управляет файрволом

#-------------- Надоедливые пакеты -------------------------------------
# защита от слишком частых соединений с одного IP для SMTP
# 2 соединения с одного IP за 1 минуту
/sbin/iptables -A INPUT -p tcp --dport 25 -m state --state NEW -m recent --set --name smtp_c1
/sbin/iptables -A INPUT -p tcp --dport 25 -m state --state NEW -m recent --update --seconds 60 --hitcount 2 --name smtp_c1 -j LOG --log-level info --log-prefix "Annoying SMTP1: "
/sbin/iptables -A INPUT -p tcp --dport 25 -m state --state NEW -m recent --update --seconds 60 --hitcount 2 --name smtp_c1 -j REJECT --reject-with icmp-host-prohibited
# 3 соединения с одного IP за 10 минут
/sbin/iptables -A INPUT -p tcp --dport 25 -m state --state NEW -m recent --set --name smtp_c2
/sbin/iptables -A INPUT -p tcp --dport 25 -m state --state NEW -m recent --update --seconds 600 --hitcount 3 --name smtp_c2 -j LOG --log-level info --log-prefix "Annoying SMTP2: "
/sbin/iptables -A INPUT -p tcp --dport 25 -m state --state NEW -m recent --update --seconds 600 --hitcount 3 --name smtp_c2 -j REJECT --reject-with icmp-host-prohibited

Строчки с правилами -j LOG можно не писать. Они пишут с системный лог сообщения о срабатывании защиты.

В дистрибутивах Fedora и Centos настройки файрвола находятся в файле /etc/sysconfig/iptables.
Подобные строчки нужно вставить перед разрешением приёма входящих соединений на 25 порт.
Например так:

-A INPUT -p tcp --dport 25 -m state --state NEW -m recent --set --name smtp_c1
-A INPUT -p tcp --dport 25 -m state --state NEW -m recent --update --seconds 60 --hitcount 2 --name smtp_c1 -j LOG --log-level info --log-prefix "Annoying SMTP1: "
-A INPUT -p tcp --dport 25 -m state --state NEW -m recent --update --seconds 60 --hitcount 2 --name smtp_c1 -j REJECT --reject-with icmp-host-prohibited
-A INPUT -p tcp --dport 25 -m state --state NEW -m recent --set --name smtp_c2
-A INPUT -p tcp --dport 25 -m state --state NEW -m recent --update --seconds 600 --hitcount 3 --name smtp_c2 -j LOG --log-level info --log-prefix "Annoying SMTP2: "
-A INPUT -p tcp --dport 25 -m state --state NEW -m recent --update --seconds 600 --hitcount 3 --name smtp_c2 -j REJECT --reject-with icmp-host-prohibited
...
-A INPUT -p tcp -m state --state NEW -m tcp --dport 25 -j ACCEPT

Защита от перебора ящиков внутри одного соединения

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

Вот как выглядит сессия

Dec 5 13:07:24 www sendmail[27536]: pB597MvU027536: ... User unknown
Dec 5 13:07:24 www sendmail[27536]: pB597MvU027536: ... User unknown
Dec 5 13:07:24 www sendmail[27536]: pB597MvU027536: ... User unknown
Dec 5 13:07:24 www sendmail[27536]: pB597MvU027536: ... User unknown

В стандартной поставке sendmail у Федоры нет защиты от перебора имён пользователей. Однако начиная с версии 8.14.3 в исходниках sendmail’а такая штука есть. Кроме того есть отдельные патчи для версии 8.14.2.
Штука эта называется confBAD_RCPT_SHUTDOWN, и она сбрасывает соединение, если количество неизвестных пользователей превысит указанную величину.

Чтобы включить эту опцию необходимо будет скомпилировать sendmail с опцией _FFR_BADRCPT_SHUTDOWN.

Сачиваем исходники sendmail и устанавливаем пакет с исходниками для компиляции.
Я всё это делал из под root’а. Поэтому все исходники появлялись в папке /root/rpmbuild

yumdownloader --source sendmail
rpm -i ./sendmail-8.14.5-11.fc16.src.rpm

Необходимые пакеты для сборки
tcp_wrappers-devel
libdb-devel
hesiod-devel
groff
ghostscript
m4
systemd-units

Ставим недостающие:

yum install tcp_wrappers-devel libdb-devel hesiod-devel groff ghostscript m4 systemd-units -y

К сожалению простой перекомпиляцией дело не обойдётся. Если мы хотим, чтобы наши настройки работали в файле sendmail.mc, то необходимо пропатчить ещё и файл sendmail-8.14.5/cf/m4/proto.m4 в котором как раз и описано включение этой опции при преобразовании sendmail.mc в sendmail.cf.
Почему то эти изменения не включены в стандартную поставку исходников sendmail от Федоры я не знаю.

Копируем патч для файла proto.mc sendmail-8.14.5-m4-bad-rcpt-shutdown.patch в папку ~/rpmbuild/SOURCES

Правим spec-файл ~/rpmbuild/SPECS/sendmail.spec

Правим релиз,

Release: 11%{?dist}

чтобы можно было понять, что это наш пакет, а не федоровский. Например так:

Release: 11.feser16

После всех PatchXX: вставляем названия своего патча

Patch27: sendmail-8.14.5-m4-bad-rcpt-shutdown.patch

И после всех %patchXX

%patch27 -p1 -b .bad-rcpt-shutdown

Число у Patch выбирается по порядку после последнего.

В строчку флагов компиляции
Добавляем опцию -D_FFR_BADRCPT_SHUTDOWN вот так:

define(\`confENVDEF', \`-I%{_includedir}/libdb -I/usr/kerberos/include -Wall -DXDEBUG=0 -DTCPWRAPPERS -DNETINET6 -DHES_GETMAILHOST -DUSE_VENDOR_CF_PATH=1 -D_FFR_TLS_1 -D_FFR_LINUX_MHNL -D_FFR_QOS -D_FFR_BADRCPT_SHUTDOWN')

Spec-файл отредактиррован — можно начать компиляцию пакетов

rpmbuild -bb --target=`uname -m` sendmail.spec

В конфигурацию sendmail.mc добавляем

dnl Обрыв соединения при частых неправильных RCPT.
define(`_FFR_BADRCPT_SHUTDOWN')dnl
define(`confBAD_RCPT_SHUTDOWN', `2')dnl после двух неверных адресов сбрасываем соединение
define(`confBAD_RCPT_SHUTDOWN_GOOD', `0')dnl на процент хороших и не смотрим

Устанавливаем пакеты. Собранные пакеты находятся у меня в каталогах ~/rpmbuild/RPMS/i686 и ~/rpmbuild/RPMS/noarch
Например так:

cd ~/rpmbuild/RPMS/i686
yum localupdate sendmail-8.14.5-11.feser16.i686.rpm ../noarch/sendmail-cf-8.14.5-11.feser16.noarch.rpm

Перезапускаем сервис

service sendmail restart

Кроме того может быть имеет смысл поставить опцию в конфигурации sendmail.mc
define(`confBAD_RCPT_THROTTLE’, `1′)dnl
Она поможет снизить назрузку на систему при сильной атаке ботнета.
После приёма несуществующего адреса наша система будет запрашивать следующий адрес уже с задержкой в 1 секунду.
Задержку изменить нельзя. Но есть патчи на sendmail.

Итоги
Мы получили достаточно устойчивую систему, противодействующую большинству атак ботнета спамеров.
К сожалению, пока я настраивал эту систему ботнет перебором узнал мой реальный почтовый ящик.
Я всё равно получаю немного спама 1-2 в неделю именно на мой конкретный ящик.

Что не поможет в нашей ситуации
Опции sendmail SMTP_MAILER_MAXMSGS и SMTP_MAILER_MAXRCPTS задают максимальное число сообщений и адресатов за сессию на удалённые системы. Эти опции не работают на входящие соединения.