Данная статья является логическим продолжением статьи "Интеграция почтового анти-спама rspamd с opensmtpd" из-за некоторого вызова, который мне бросили, сказав, что сложно реализовать greylisting в связке opensmtpd+rspamd.
"Историй успеха" интеграции greylisting в opensmtpd я не встречал (если они существуют, то просьба написать в комментариях).
Что реализовать greylisting в моём случае сложно — я не отрицал и не собирался делать данный функционал до того, как в opensmtpd реализуют фильтры, хотя и понимал, что greylisting — одна из неплохих методик борьбы со спамом. Но брошенный вызов и желание ещё немного снизить количество спама и спать спокойно — не дали спать спокойно и заставили сделать это.
Мне удалось реализовать простой способ greylisting'а.
Несколько уточнений:
Способ простой только для того случая, если реализация связки opensmtpd+rspamd сделана через скрипт-прослойку mda.
Реализация greylisting'а для opensmtpd существует через фильтр. Но, как знают, заинтересованные в opensmtpd лица, стабильной реализации фильтров в opensmtpd нет. Кроме того, не хотелось добавлять ещё один демон при наличии встроенного грейлистинга в rspamd.
Реализация грейлистинга для opensmtpd существует для freebsd и spamd. Подробностями реализации не интересовался, т.к. демона spamd под linux нет.
- Реализация является костылём и использованием недокументированных возможностей, но куда мы без них в 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"
}
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
Итого
Ещё меньше спама.
Комментарии (7)
cebka
01.02.2017 14:52Rspamd делает грейлистинг не только по sender/ipnet, но и по partial body hash. Так что никаких проблем с gmail или кривыми клиентами не будет.
Ну и есть, конечно же, whitelist'ы по spf/dkim/dmarc: https://rspamd.com/doc/modules/whitelist.html
С грейлистингом и рейтлимитами вполне себе можно передать удаленному MTA, через сколько ему посылать в следующий раз (например, сейчас модуль ratelimit так и делает). Другое дело, что такие сообщения не стандартизованы, хотя об этом идет дискуссия в m3aawg.
acmnu
01.02.2017 16:41Хм. А смысл в таких сообщениях? Как только их стандартизируют спамеры начнут их использовать.
Собственно популярность грейлиста уже многими ботнетами учитывается и если ваш адрес попал в некий узкий лист, то высока вероятность, что повтор будет сделан как надо.
cebka
01.02.2017 17:21Хм. А смысл в таких сообщениях? Как только их стандартизируют спамеры начнут их использовать.
Ну и пусть используют. Чем им это поможет-то?
Собственно популярность грейлиста уже многими ботнетами учитывается и если ваш адрес попал в некий узкий лист, то высока вероятность, что повтор будет сделан как надо.
Поэтому грейлистинг бесполезен, да?
acmnu
01.02.2017 17:42Поможет ещё как. Сейчас они фактически не знаю, проблема это или грейлист, а тут им прямым текстом будут говорить: зайди через пять минут. И ведь таки придут.
cebka
01.02.2017 18:42Поможет ещё как. Сейчас они фактически не знаю, проблема это или грейлист, а тут им прямым текстом будут говорить: зайди через пять минут. И ведь таки придут.
А то, что сейчас им возвращают временную 400-ю ошибку и что-то вроде 'Try again later', вас никак не смущает?
acmnu
Сложности с грейлистом довольно большие наблюдаю я сейчас.
Во-первых, многие (те кто базируется на решениях MS) внедрили у себя защиту от спама на основе генерации липовых sender. Каждая посылка или перепосылка сообщения будет вестись от некого липового сендера с псевдорандомным local part. Таким образом грейлистить по sender стало трудновато.
Во-вторых, есть проблемы с большими сетями: mail.ru, gmail.com, yandex.ru и особенно outlook.com имеют кучу выходных MTA. Outlook.com особенно неприятен, поскольку всегда перепосылает с другого сервера, в отличии от yandex.ru, например. Правило /19, о котором говорится в статье, мне кажется не самым удачным. С одной стороны сетка у тех же MS может быть и шире /19, а с другой могут начаться ложно положительные срабатывания, когда две машины спамера находятся в пределах одной /19 сети. Короче баланс тут поймать очень сложно.
И в-третьих, проблема согласования времени повторов. К сожалению нет такого стандрата: грейлист. Это просто грязный хак. Для отправляющего сервера это выглядит как defer — временная проблема доставки. И тайминги повтора определяются каждым поставщиком индивидуально. Например все крупные игроки, стараются перепослать письмо очень быстро с этого же MTA (кроме outlook.com). Я так думаю, что с их бешенным поток им крайне не выгодно раздувать очередь, поэтому письма имеют короткий ретри на том же MTA, а потом падают на дополнительные MTA специализирующиеся на повторной доставке. А таймаут грейлиста обычно стоит на 5 минут. И в случае с yandex.ru, например, за эти пять минут он уже раза три к вам стукнется, плюнет и уйдет уже минут на десять. Это вносит раздражение для персонала. На деле, если не угадать с таймаутом, то письмо может прийти и через полчаса и через час.
Я с этим боролся следущим образом.
Для начала был составлен список условно доверенных доменов: это крупные игроки плюс все те домены, на которые хоть раз писал один из наших сотрудников (роботы не в счет).
Если приходит письмо с сендером из этого домена, то я снача проверяю spf на строгое положительное совпадение (~all разумеется не учитывается). Если совпало, то грейлист отключается. Если spf нет, то я проверяю на строгое соответствие MX или A записи для ip. Если и это не помогло, то тогда все это падает в greylist и собирается для оценки в качестве еженедельного отчета.
В качестве ключа я нынче использую домен, взятый из sender, ip MTA и rcpt. Т.е. из классики я выкинул только local part of sender.
acmnu
А сам грейлист, к слову, это два шелл скрипта на входном MTA: один создает файл в имени которого ключ, а другой чистит его через сутки, если он не стал белым.