Alex 'AdUser' Z
9 years ago
3 changed files with 239 additions and 3 deletions
@ -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 .*\[<HOST>\] |
||||
SMTP protocol synchronization error \(next input sent too soon: pipelining was not advertised\): rejected .*\[<HOST>\] |
||||
rejected EHLO from \[<HOST>\]: syntactically invalid argument |
||||
rejected HELO from \[<HOST>\]: syntactically invalid argument |
||||
Connection from \[<HOST>\] refused: too many connections from that IP address |
||||
\[<HOST>\] .* host is listed in zen.spamhaus.org |
||||
\[<HOST>\] .* host is listed in bl.spamcop.net |
||||
\[<HOST>\] .* Bad rev hostname \(.*\) |
||||
\[<HOST>\] .* relay not permitted |
||||
\[<HOST>\] .* too many connections from that IP address |
||||
\[<HOST>\] .* IP address in HELO |
||||
\[<HOST>\] .* HELO should be FQDN |
||||
\[<HOST>\] .* localhost is a silly HELO |
||||
\[<HOST>\] .* Using my HELO is a bad idea |
||||
\[<HOST>\] .* SPF for sender domain not allows mail from your host |
||||
\[<HOST>\] .* You are blocked |
||||
\[<HOST>\] .* 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]: Себя не попиаришь - так и помрёшь в безвестности. |
Loading…
Reference in new issue