6 Сентябрь 2016

Использование статистики Spamassassin в конфигурации Exim

Using Spamassassin statistics in Exim configuration

В предыдущей статье "Подсистема оценки репутации антиспам пакета Spamassassin", помимо отражённых в заголовке, были затронуты вопросы того, как антиспам пакет Spamassassin накапливает и хранит данные об отправителях сообщений.

Если внимательно посмотреть на набор хранимых данных, то становится очевидным, что их можно применить и при конфигурировании начальных стадий процесса приёма сообщений SMTP-сервера. Учёт данных о репутации, к примеру, IP-адреса можно использовать для ограничения частоты рассылки спама с данного адреса. Это позволит, как уменьшить объёмы нежелательной почты, так и существенно сэкономить ресурсы почтового сервера. Кроме того, в данном случае будет отсутствовать необходимость в отдельной реализации специального механизма чёрных список вместе с сопутствующим ему программным кодом и базами данных.

Итак, рассмотрим пример использования данного подхода на базе использования его при конфигурировании Exim.

1. Конфигурирование баз данных

root@beta:~ # exim --version | head -n1
Exim version 4.87 #0 (FreeBSD 11.0) built 02-Sep-2016 03:03:44

Совместно с ним используется Spamassassin совместно с модулем оценки репутации TxRep с базой данных spamassassin, хранимыми на MySQL. Там же хранятся и учётные записи доменов и пользователей, которых обслуживает данный почтовый сервер в отдельной базе данных exim.

root@beta:~ # mysql -uroot -p
Enter password:
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 724
Server version: 5.7.13-log Source distribution
...
root@localhost [(none)]> root@localhost [(none)]> SHOW TABLES FROM spamassassin;
+------------------------+
| Tables_in_spamassassin |
+------------------------+
| awl                    |
| bayes_expire           |
| bayes_global_vars      |
| bayes_seen             |
| bayes_token            |
| bayes_vars             |
| userpref               |
+------------------------+
7 rows in set (0,00 sec)
...

Данные о репутации отправителей хранятся в таблице awl. Пример сохраняемого набора данных таков.

...
root@localhost [(none)]> SELECT * FROM `spamassassin`.`awl` ORDER BY `time` DESC LIMIT 5;
+---------------+-------------------------------------------------------+------+-------+----------+------------+---------------------+
| username      | email                                                 | ip   | count | totscore | signedby   | time                |
+---------------+-------------------------------------------------------+------+-------+----------+------------+---------------------+
| user@domain   | bodac.ru                                              | none |     1 |    8.783 | bodac.ru   | 2016-09-06 19:09:24 |
| user@domain   | 46.38.53.111                                          | none |     1 |    8.783 |            | 2016-09-06 19:09:24 |
| user@domain   | mail.bodac.ru                                         | none |     1 |    8.783 | helo       | 2016-09-06 19:09:24 |
| user@domain   | admin@bodac.ru                                        | none |     1 |    8.783 | bodac.ru   | 2016-09-06 19:09:24 |
| user@domain   | c66f96949847b9635e8fbd61afefaa99a1b0d80c@sa_generated | none |     1 |    8.783 | 1473181757 | 2016-09-06 19:09:24 |
+---------------+-------------------------------------------------------+------+-------+----------+------------+---------------------+
...

Для фильтрации хоста отправителя по IP-адресу, очевидно, что нам будут необходимы строки, содержащие такой адрес. Модуль TxRep хранит их в поле email. Для работы достаточно будет выбрать все такие данные за нужный интервал времени.

Однако, доступа к таблице awl, которая содержится в другой базе данных, у Exim нет. Решить эту проблему можно путём создания представления (VIEW) данной таблицы с требуемым для создаваемого фильтра по типу чёрного списка в базе данных exim.

...
root@localhost [(none)]> CREATE VIEW `exim`.`awl` AS SELECT `username`, `email` AS `ip`, `totscore`/`count` AS `score` FROM `spamassassin`.`awl` WHERE IS_IPV4(`email`) AND `time` > NOW() - INTERVAL 24 HOUR;
Query OK, 0 rows affected (0,01 sec)
root@localhost [(none)]> SHOW FULL TABLES IN exim WHERE TABLE_TYPE LIKE 'VIEW';
+----------------+------------+
| Tables_in_exim | Table_type |
+----------------+------------+
| awl            | VIEW       |
+----------------+------------+
2 rows in set (0,05 sec)
...

В данном случае создано преставление с именем awl где будут отображаться имя пользователя (username), IP-адрес (ip) и среднюю накопленную оценку данного хоста (score) за последние 24 часа. Вот что получилось на выходе.

...
root@localhost [(none)]> SELECT * FROM `exim`.`awl` LIMIT 5;
+----------------+----------------+--------------------+
| username       | ip             | score              |
+----------------+----------------+--------------------+
| user@domain    | 182.75.33.130  |  44.70800018310547 |
| user@domain    | 113.176.163.98 | 16.679000854492188 |
| user@domain    | 185.138.183.84 | 3.9590001106262207 |
| user@domain    | 194.67.208.50  |   17.5310001373291 |
| user@domain    | 194.67.212.248 |  3.503000020980835 |
+----------------+----------------+--------------------+
5 rows in set (0,01 sec)
root@localhost [(none)]> QUIT
Bye

2. Конфигурация Exim

После создания представления awl в базе данных exim почтового сервера для реализации чёрного списка достаточно лишь будер организовать проверку на вхождение комбинации хост отправителя - адрес получателя (в данном случае он же имя пользователя) на вхождение его в созданный список.

В качестве критерия будет использоваться накопленная средняя оценка из поля score. В данной системе используется следующая схема обработки входящего сообщения исходя из полученной им от Spamassassin оценки:

  • баллы ниже 5.0 - не спам, который доставляется в папку "Входящие";
  • баллы от 5.0 до 10.0 - спам, который доставляется в папку "Спам";
  • баллы от 10.0 до 15.0 - спам, который не доставляется пользователю, но сохраняется в специальный каталог для возможной ручной оценки и нужд розыска возможно ошибочной оценки корреспонденции;
  • и, наконец, баллы свыше 15.0, когда сообщение просто уничтожается.

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

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

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

При этом, однако, следует до возможной блокировки сделать доступной возможность доставки почты, во-первых, служебным учётным записям postmaster и abuse для того, чтобы у администратра заблокированного хоста был шанс обратиться с жалобой, во-вторых, от доверенных хостов, список которых, обычно, содержится в relay_from_hosts и, в-третьих, возможность отправки корреспонденции со стороны аутентифицированных пользователей, каковых скорринг Spamassassin вообще затрагивать не должен. Также разумно будет это сделать до проверки записи SPF и, тем более, подробного синтаксического разбора сессии дабы не заставлять сервер делать, возможно, излишнюю для данного IP-адреса работу.

root@beta:~ # cat /usr/local/etc/exim/configure
# $Cambridge: exim/exim-src/src/configure.default,v 1.14 2009/10/16 07:46:13 tom Exp $
# --- by Max Kostikov (c) 2010...2016 v.20160830
...
hide mysql_servers      = localhost/exim/user/pass
...
hostlist relay_from_hosts       = 127.0.0.1 : localhost
...
acl_smtp_rcpt           = acl_check_rcpt
acl_smtp_dkim           = acl_check_dkim
acl_smtp_mime           = acl_check_mime
acl_smtp_data           = acl_check_data
...
begin acl
acl_check_rcpt:
...
  # --- deny hosts with bad reputation
  deny   condition      = ${lookup mysql{SELECT `score` FROM `awl` WHERE \
                          `username` = '${quote_mysql:$local_part@$domain}' AND \
                          `ip` = '$sender_host_address' AND `score` > '10'}{true}{false}}
         message        = Your IP temporary banned due bad reputation
...

Не забыв перезапустит службу Exim через некоторое время в лог-файлах можно увидеть полученный результат.

root@beta:~ # cat /var/log/maillog | grep reputation
Sep  6 00:00:01 beta exim[13253]: H=mail.holihik.co.ua (holihik.co.ua) [217.172.177.226] I=[10.10.10.10]:25 F=<ospudkd@holihik.co.ua> rejected RCPT <user@domain>: Your IP temporary banned due bad reputation
Sep  6 01:34:17 beta exim[14114]: H=mail.gomelins.co.ua (gomelins.co.ua) [62.75.177.7] I=[10.10.10.10]:25 F=<amwibqc@gomelins.co.ua> rejected RCPT <acme@domain>: Your IP temporary banned due bad reputation
Sep  6 01:36:41 beta exim[14120]: H=s1.bizneroa.co.ua (bizneroa.co.ua) [85.25.151.19] I=[10.10.10.10]:25 F=<iknoszj@bizneroa.co.ua> rejected RCPT <user@domain>: Your IP temporary banned due bad reputation
Sep  6 01:54:42 beta exim[14303]: H=mail.geremans.co.ua (geremans.co.ua) [85.25.152.209] I=[10.10.10.10]:25 F=<iwdazyq@geremans.co.ua> rejected RCPT <acme@domain>: Your IP temporary banned due bad reputation
Sep  6 02:00:09 beta exim[14616]: H=s1.mclarens.co.ua (mclarens.co.ua) [85.25.13.210] I=[10.10.10.10]:25 F=<ahfivrp@mclarens.co.ua> rejected RCPT <acme@domain>: Your IP temporary banned due bad reputation
Sep  6 02:06:09 beta exim[14711]: H=mail.holihik.co.ua (holihik.co.ua) [217.172.177.226] I=[10.10.10.10]:25 F=<etdujqn@holihik.co.ua> rejected RCPT <acme@domain>: Your IP temporary banned due bad reputation
...

Безусловно, эта реализация чёрного списка самая простая по логике работы и программному коду, но, несмотря на это, она весьма эффективна и более чем полезна.

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

3. PROFIT!

Статья была полезной? Тогда прошу не стесняться и поддерживать деньгами через PayPal или Яндекс.Деньги.