diff --git a/articles/2016/04/10/hardcore-mail-relay-1/index.markdown b/articles/2016/04/10/hardcore-mail-relay-1/index.markdown index 6daea22..7ac7a1c 100644 --- a/articles/2016/04/10/hardcore-mail-relay-1/index.markdown +++ b/articles/2016/04/10/hardcore-mail-relay-1/index.markdown @@ -14,13 +14,12 @@ tags: mail, spam, exim, zabbix, rspamd, репост * литература и ссылки - [Статистика и мониторинг](/articles/2016/04/10/hardcore-mail-relay-2/) - [Настройки средств самого exim'а](/articles/2016/04/11/hardcore-mail-relay-3/) -- Усиливаем защиту внешними средствами +- [Усиливаем защиту внешними средствами](/articles/2016/04/15/hardcore-mail-relay-4/) * отстрел ботов * грейлистинг * DKIM * антиспам * антивирус - * заметки на полях по поводу платных антивирусов под *nix - Обратная связь и переобучение системы * переобучение антиспама * репутация доменов diff --git a/articles/2016/04/11/hardcore-mail-relay-3/index.markdown b/articles/2016/04/11/hardcore-mail-relay-3/index.markdown index bfc42f4..2a4f79f 100644 --- a/articles/2016/04/11/hardcore-mail-relay-3/index.markdown +++ b/articles/2016/04/11/hardcore-mail-relay-3/index.markdown @@ -381,4 +381,4 @@ tags: mail, spam, exim --- -[К оглавлению](/articles/2016/04/10/hardcore-mail-relay-1/) +[К оглавлению](/articles/2016/04/10/hardcore-mail-relay-1/), [Далее: Усиливаем защиту внешними средствами](/articles/2016/04/15/hardcore-mail-relay-4/) diff --git a/articles/2016/04/15/hardcore-mail-relay-4/index.markdown b/articles/2016/04/15/hardcore-mail-relay-4/index.markdown new file mode 100644 index 0000000..aa272b3 --- /dev/null +++ b/articles/2016/04/15/hardcore-mail-relay-4/index.markdown @@ -0,0 +1,237 @@ +--- +title: Почтовый шлюз: задание со звёздочкой (Усиливаем защиту внешними средствами) +tags: mail, spam, exim +--- + +Под "внешними средствами" я понимаю дополнительный софт, без которого впринципе можно и обойтись. +Однако, если его применение облегчит нам жизнь, снизит количества спама или замедлит рост энтропии - почему бы и нет. + +--- + +Отстрел ботов +------------- + +Сейчас практически must-have для почтового сервера. Резко снижает содомию в логах, и загрузку всей остальной системы за счёт меньшей работы антимпама/антивируса/dns'а и т.д. + +Для этой задачи вы можете использовать или "старый добрый" fail2ban или мою разработку -- [f2b](http://linuxdv.org/articles/2016/03/17/f2b/)[^fn1]. + +Настройку fail2ban вы и без меня осилите, т.к. оно достаточно индивидуально, привожу только failregex. +Всё что ниже 5й линии - это сообщения из соответствующих проверок ``acl_smtp_helo`` и ``acl_smtp_rcpt``. + + failregex = SMTP protocol synchronization error \(input sent without waiting for greeting\): rejected connection from .*\[\] + SMTP protocol synchronization error \(next input sent too soon: pipelining was not advertised\): rejected .*\[\] + rejected EHLO from \[\]: syntactically invalid argument + rejected HELO from \[\]: syntactically invalid argument + Connection from \[\] refused: too many connections from that IP address + \[\] .* host is listed in zen.spamhaus.org + \[\] .* host is listed in bl.spamcop.net + \[\] .* Bad rev hostname \(.*\) + \[\] .* relay not permitted + \[\] .* too many connections from that IP address + \[\] .* IP address in HELO + \[\] .* HELO should be FQDN + \[\] .* localhost is a silly HELO + \[\] .* Using my HELO is a bad idea + \[\] .* SPF for sender domain not allows mail from your host + \[\] .* You are blocked + \[\] .* Dont like your hostname + +Обратите внимание - используются не все проверки. Логика отбора такая: под раздачу должны попадать хосты, у которых есть какой-то серьёзный косяк, и которые продолжают настойчиво к нам ломиться. + + [exim] + findtime = 300 # если в последние T секунд ... + maxretry = 5 # .. было N срабатываний для одного и того же ip .. + bantime = 3600 # .. отправить его отдохнуть на часик + logpath = /var/log/exim/mainlog + enabled = true + filter = exim-custom + +f2b настраивается примерно так (только описание самого jail'а): + + [jail:postfix] + enabled = yes + source = files:/var/log/mail.log + filter = preg:/etc/f2b/filters/postfix.preg + backend = exec-ipset:banned + bantime = 3600 + +Грейлистинг +----------- + +В приведённом ранее конфиге были места, где устанавливался флаг, что этот хост нужно проверить грейлистингом, однако самой проверки не было. + +Для реализации грейлистинга используется sqlgrey. Спроектирован он изначально под postfix, и его ``check_policy``, здесь это придётся костылять средствами exim'а. + +В acl ``check_rcpt``, поближе к концу, но перед ``accept domains = +our_domains``: + + # greylisting + defer message = Service temporarily unavailable, try again later + condition = ${if eq{$acl_m_greylist}{1} {yes}{no}} + set acl_m0 = request=smtpd_access_policy\nprotocol_state=RCPT\nprotocol_name=${uc:$received_protocol}\nhelo_name=$sender_helo_name\nclient_address=$sender_host_address\nclient_name=$sender_host_name\nsender=$sender_address\nrecipient=$local_part@$domain\ninstance=$sender_host_address/$sender_address/$local_part@$domain\n\n + set acl_m0 = ${sg{${readsocket{/var/run/sqlgrey.sock}{$acl_m0}{5s}{}{action=DUNNO}}}{action=}{}} + condition = ${if eq{${uc:${substr{0}{5}{$acl_m0}}}}{DEFER} {yes}{no}} + +Выглядит оно достаточно страшно, но тем не менее работает. + +Обратите внимание на используемые переменные вида ``acl_m*`` -- они раскрываются для каждого сообщения, поскольку грейлистинг использует триплеты senderip-from-rcpt. +Это также означает, что мы можем использовать эту проверку только в пределах ``acl_smtp_rcpt``. + +Справочно, конфиг самого sqlgrey: + + unix = /var/run/sqlgrey.sock + reconnect_delay = 10 + max_connect_age = 24 + awl_age = 32 + group_domain_level = 10 + db_type = SQLite + db_name = /var/db/sqlgrey/stats.db + optmethod = optout + +DKIM +---- + +В exim'е есть базовая поддержка dkim'а, надо только чтобы она была включена при компиляции. + +Этот блок - дописывается в начало файла exim'а: + + DKIM_DOMAIN = ${lc:${domain:$h_from:}} + DKIM_FILE = /etc/exim/${lc:${domain:$h_from:}}.key + DKIM_PRIVATE_KEY = ${if exists{DKIM_FILE}{DKIM_FILE}{0}} + +...и добавляем три строчки к транспорту ``remote_smtp``: + + remote_smtp: + driver = smtp + interface = 4.3.2.1 + no_delay_after_cutoff + # ага, вот эти ребята + dkim_domain = DKIM_DOMAIN + dkim_selector = dkim + dkim_private_key = DKIM_PRIVATE_KEY + +Антиспам +-------- + +В нашем варианте в качестве антиспама используется rspamd. +spamassassin прикручивается почти так же, надо поменять ``variant=`` +и подправить проверку переменной ``$spam_action`` + +Про донастройку rspamd я отдельно расскажу, здесь только как его подключить к exim'у. + +Вот этот блок - в начало конфига. + + spamd_address = 127.0.0.1 11333 variant=rspamd + +А этот - дописать в acl ``check_data``, чтобы он принял примерно такой вид: + + check_data: + # не проверять сообщения с наших собственных серверов + accept hosts = +our_networks : +our_hosts : +relay_from_hosts + + # пропускать всё с "наших" доменов + # с проверкой, что письмо от "нашего" домена идёт с "наших" хостов - + # надо было разбираться раньше + accept sender_domains = +our_domains + + # не проверять сообщения, если используется submission + accept condition = ${if eq {$interface_port}{587} {yes}{no}} + + # не проверять юзеров, которые авторизовались в системе + accept authenticated = * + + # это правило как раз и отправляет письмо на проверку антиспамом + # nobody - это "профиль пользователя" в антиспаме + warn spam = nobody:true + + # тут - проверка антивирусником, смотри далее + + # если письмо набрало больше порога - отлуп + deny condition = ${if eq{$spam_action}{reject}} + message = Message discarded as high-probability spam + + # если антиспам считает письмо "хорошим" - добавить хидер + # потом это поможет в разбирательствах, попало письмо в проверку или нет + accept condition = ${if eq{$spam_action}{no action} {yes}{no}} + add_header = X-Spam-Status: No + + # если письмо набрало сколько-то баллов, но недобрало до отлупа - + # добавляем дополнительную информаию для дальнейших разбирательств + # + # я дальше покажу как отловить такие письма и сложить отдельно + accept condition = ${if eq{$spam_action}{add header} {yes}{no}} + add_header = X-Spam-Status: Yes + add_header = X-Spam-Score: $spam_score ($spam_bar) + add_header = X-Spam-Report: $spam_report + + # ну ладно, так уж и быть - пущу + accept + +Антивирус +--------- + +Антивирусов под линуксом немного, запутаться сложно. +По дефолту показываю на примере clamav, если у вас что-то другое - исправляйте под свои реалии. + +В начало конфига, к общим настройкам: + + av_scanner = clamd:/var/run/clamav/clamd.sock + +В секцию acl'ов, дописать в середину ``check_data``: + + check_data: + <...> + # discard viruses and malware + deny malware = */defer_ok + message = This message was detected as possible malware + +``defer_ok`` - говорит серверу при недоступности антивирусника или его кривой настройкой, +отвечать 4XX ошибками - "сервис временно недоступен" (вместо 5XX). Почта не пропадёт. + +Немного про эффективность clamd: официальные базы ловят немного, и обновляются весьма неспешно, +по моим наблюдениям - примерно пятую часть от новья и половину от старых. +Разгребая спецящик "под спам" в день находишь 2-3 бинарника/архива. Смотришь логи clamav, но уже за неделю - те же 2-3 шт. +Хотя надо учитывать ещё две вещи - наличие DNSBL/XBL (думаю, без них до clamav доходило бы намного больше) и сам характер непойманных "вирусов". + +Примеры из непойманного: + +* zip-архив, внутри - js-скрипт с eval'ом. Не знаю на кого это рассчитано и как оно намеревалось запускаться. +* запароленные архивы, пароль указан в самом письме. Часть из них clamav всё же ловит, но не всё. +* rar, переименованный в маргинальщину типа .ace. Это рассчитано на winrar, который жрёт всё. Такое clamav должен ловить. + +Чтобы победить эту напасть и повысить уловы, рекомендуют заюзать неофициальные базы: [тыц](https://github.com/extremeshok/clamav-unofficial-sigs) +Часть из них платные, часть - полностью свободные. При подключении части этих баз, отсекается порядка 80% случаев, типа описанных выше. + +Потребление памяти в процессе работы (до 20 писем/мин): ~350 метров. + +Если есть желание пополнить базу, вот скриптик в помощь: + + #!/bin/sh + # исправьте на свои + USER="Alex Z" + EMAIL="ad_user@runbox.com" + # нет прокси - убрать или закомментировать + PROXY="http://192.168.49.1:8080" + export http_proxy="$PROXY" + export https_proxy="$PROXY" + + ls *.zip 2> /dev/null | while read ZIP; do + unzip "$ZIP" \ + && rm -vf "$ZIP" + done + + ls *.exe *.ace *.scr *.jar *.doc *.vbs 2> /dev/null | while read FILE; do + echo "Processing $FILE" + clamsubmit -N "$USER" -e "$EMAIL" -n "$FILE" > /dev/null \ + && rm -vf "$FILE" + done + +Выделяем где-нибудь отдельную директорию, кладём туда этот скриптик, накидываем "улов" и запускаем. +Занимает времени - полминуты, но повышает ЧСВ на 100500. + +Опять же по опыту, добавляют в базу примерно 1/30 образцов. + +--- + +[К оглавлению](/articles/2016/04/10/hardcore-mail-relay-1/) + +[^fn1]: Себя не попиаришь - так и помрёшь в безвестности.