Простой greylisting в opensmtpd

в 21:17, , рубрики: opensmtpd, rspamd

Данная статья является логическим продолжением статьи "Интеграция почтового анти-спама rspamd с opensmtpd" из-за некоторого вызова, который мне бросили, сказав, что сложно реализовать greylisting в связке opensmtpd+rspamd.

"Историй успеха" интеграции greylisting в opensmtpd я не встречал (если они существуют, то просьба написать в комментариях).

Что реализовать greylisting в моём случае сложно — я не отрицал и не собирался делать данный функционал до того, как в opensmtpd реализуют фильтры, хотя и понимал, что greylisting — одна из неплохих методик борьбы со спамом. Но брошенный вызов и желание ещё немного снизить количество спама и спать спокойно — не дали спать спокойно и заставили сделать это.

Мне удалось реализовать простой способ greylisting'а.

Несколько уточнений:

  1. Способ простой только для того случая, если реализация связки opensmtpd+rspamd сделана через скрипт-прослойку mda.

  2. Реализация greylisting'а для opensmtpd существует через фильтр. Но, как знают, заинтересованные в opensmtpd лица, стабильной реализации фильтров в opensmtpd нет. Кроме того, не хотелось добавлять ещё один демон при наличии встроенного грейлистинга в rspamd.

  3. Реализация грейлистинга для opensmtpd существует для freebsd и spamd. Подробностями реализации не интересовался, т.к. демона spamd под linux нет.

  4. Реализация является костылём и использованием недокументированных возможностей, но куда мы без них в IT?

Теория

Greylisting — методика отброса спама, основанная на том, что спам-программы хотят разослать как можно больше спама здесь и в данную секунду.

Упрощённая логика грейлистинга: если к нам приходит письмо, то мы отвечаем отправителю временной ошибкой, сами запоминаем отправителя (например, на сутки) для того, чтобы принять от него письмо через некоторое время (например, через 5 минут).

"Правильный" отправитель (согласно стандартам) должен попытаться отправить нам письмо ещё раз через некоторое время. "Неправильный" отправитель этого или не делает или делает, но за прошедшее время отправитель успевает попасть в различные внешние спам-списки и мы его отфильтровываем уже на основании этих спам-списков.

После того, как мы отправителя запомнили, то в течение суток (как пример), проверка на грейлисты не делается повторно. Это позволяет сократить время доставки повторного письма (если это правильный отправитель).

В postfix+amavis+spamasassin greylisting делался, если не ошибаюсь, по доменным именам. В rspamd ключём для greylisting'а сделан IP адрес отправителя с маской /19 (конфигурируемо). Со стороны всеобщей кластеризации и гео-распределённых сервисов — это выглядит как более правильное решение, но и обсуждаемое, с другой стороны.

К сожалению, всё вышесказанное в теории выглядит хорошо, но на практике, когда на чайниках, микроволновках и компьютерах обычных пользователей существует множество ботнетов, которые рассылают спам через обычный Outlook (как он там, существует ещё до сих пор на Windows?) — всё не так замечательно. Но как-то методика работает и отказываться от неё не стоит.

Практика

redis в rpsamd

Включаем поддержку редиса в rpsamd. Модуль грейлистинга хранит в редисе свои данные.

# /etc/rspamd/local.d/redis.conf
servers = "redis.example.com";
password = "example_password";

Запускаем редис (в докере, например, это делается одной командой).

greylisting в rspamd

Включаем модуль грейлистинга (по умолчанию, он выключен). expire — время, на которое отправитель становится доверенным, после прохождения проверки. Я специально подкрутил побольше. По умолчанию — 86400 секунд.

# /etc/rspamd/modules.d/greylist.conf
greylist {
  expire = 864000;

  .include(try=true,priority=5) "${DBDIR}/dynamic/greylist.conf"
  .include(try=true,priority=1,duplicate=merge) "$LOCAL_CONFDIR/local.d/greylist.conf"
  .include(try=true,priority=10) "$LOCAL_CONFDIR/override.d/greylist.conf"
}

Пример контейнера с rspamd

greylisting в opensmtpd

Самая неоднозначная часть решения.

После того, как мы отправили письмо демону rspamd через клиент rspamc (см. предыдущую статью) — демон нам на STDOUT отвечает текстом письма с добавленными заголовками.

В случае, если требуется greylisting, то в заголовках будет присутствовать "X-Spam-Action: soft reject". По хорошему, mta или фильтры распознают этот заголовок и отвечают отправителю временной ошибкой.

Но у нас нет поддержки mta или фильтров. Поэтому, мы просто делаем exit 1!

# см. скрипт из предыдущий статьи
greylisted=$( cat $mail_file | fgrep 'X-Spam-Action: soft reject' )
if [ -n "$greylisted" ]; then
  exit 1
fi

opensmtpd, получив код возврата 1, понимает, что что-то пошло не так и за нас отвечает отправителю временной ошибкой.

Особенности запуска docker контейнера с opensmtpd: его нужно запускать в режиме сети "host", чтобы демон видел корректные IP адреса отправителей.

Пример контейнера с opensmtpd

Итого

Ещё меньше спама.

Автор: neenik

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js