Принудительная /
обязательная smtp-аутентификация sendmail. Правила (Rules) конфигурационного файла.
Настраивая sendmail столкнулся с довольно непонятной по современным меркам
ситуацией: фактически любой пользователь (внешней сети или внутренней) может от
имени сервера рассылать спам!!! То есть,
хотя бы так:
> telnet MyDomainSendmailServer.com 25
> ehlo MyDomainSendmailServer.com
> Mail from:<serg@MyDomainSendmailServer.com>
> RCPT To:<BillGates@microsoft.com>
> Data
(конечно, надо знать чей-то ящик домена, который засветился
в сети)
В принципе, всё по стандартам и вполне логично. Ведь
сотрудник может работать не только на самом предприятии через локальную сеть, а
может куда-то уехать в другую страну, и захочет иметь доступ к почте. Что же
тогда делать, как бороться если кто-то начнет таким образом рассылать тысячи
спам-писем из нашего домена??? А ответа нормального похоже не существует. Если
почтой пользуются только на рабочем месте, то еще можно что-то настроить через relay. Но когда кто-то должен
пользоваться smtp-сервером
из вне, то ситуация плачевная. Есть, конечно, разные способы борьбы, хотя бы
вставлять паузы перед приглашением (greet_pause),
но такая защита курам на смех. Единственный логичный вариант, чтобы при
отправке письма запрашивало пароль. Это и есть smtp-авторизация.
Как её настраивать можете найти в Интернете – ресурсов хватает. Но в этом
способе есть критические недостатки, которые фактически нивелируют всю
проделанную работу:
1) smtp-авторизация
не является обязательной. То есть, если вы и не прошли авторизацию, то можно и
без неё.
2) Можно настроить сервер с обязательной авторизацией: DAEMON_OPTIONS(`...,
m=a’)
Однако, тогда ни один сервер не сможет прислать почту на ваш
домен. Ведь стороннему серверу (gmail/mail.ru/yandex.ru)
нужно ввести какой-то пароль…
В Интернете нарыл способ конфигурационным файлом создать принудительную
авторизацию. И этот способ, похоже, является единственной надеждой. Попросту
странно, что это не входит в базовые конфигурации серверов электронной почты.
Говорят, что такое манипуляции могут пригодиться раз в жизни – настроил и
забыл, но если это нужно всем, зачем же тогда изобретать велосипед каждому?
И так, код:
LOCAL_CONFIG Ksyslog syslog
LOCAL_RULESETS
SLocal_check_rcpt
# empty address?
R<> $#error $@ nouser $: "553 User address required"
R$@ $#error $@ nouser $: "553 User address required"
#Добавляем адрес отпрвителя
R$* $: $1 $| $&f
#Канонизируем адреса
R$* $| $* $: $2 $| $>Parse0 $>3 $1
R$* $| $* $: $2 $| $>Parse0 $>3 $1
#Ксли отправитель и получатель локальные, отправляем их на проверку в CheckLocalAuth
R$+<@$=w.> $| $+<@$=w.> $: $>CheckLocalAuth
#Другие варианты fqdn-адресов пропускаем (внеш-внеш, внутр-внеш, внеш-внутр)
R$+<@$+> $| $+<@$+> $@ $1
#Алиасы, MAILER-DAEMON и др. лок. получатели без доменной части - в ту же проверку
R$+ $| $+ $: $>CheckLocalAuth
#Контрольная проверка - кто там не охвачен нашими правилами: если сработает - покажешь, подправим
R$* $: $(syslog syslog:PROBLEM: $1 $) $1
SCheckLocalAuth
#Почту с самого сервера пропускаем
R$* $: $&{client_addr}
R127.0.0.1 $@OK
#Если авторизация имела место - пропускаем
R$* $: < $&{auth_authen} >
R< $+ > $@ OK
#Все остальное блокируем
R$* $#error: $: 553 Sorry, you must use smtp-authentication. Please, contact to postmaster.
Пояснение кода
Долго пытался понять, что этот весь код выше означает.
Оказалось, что на русском языке даже нет документации по этим командам (лишь частичную)!
Пришлось качать заграничную Costales B., Jansen G., Aßmann C. «sendmail».
До конца весь код я сам не понял, но то, что именно нам
нужно - поясню. Но начнём с основ.
Ликбез
Каждое правило (Rules) начинается с буквы «R». Затем идут так званые левое поле и право поле. Они должны
быть разделены табуляцией (это обязательно). Работают правила так: В некой
памяти (назовём её WorkSpace)
находится какая-то информация. Эта информация сравнивается с шаблоном левого
поля, и если совпадение осуществилось, то в WorkSpace записывается то, что в правом
поле. Пример:
Допустим WorkSpace=xxx
И имеем правило:
R xxx yyy
Так как WorkSpace совпадает с шаблоном «xxx», значит в WorkSpace будет помещено «yyy». То есть, на языках
программирования это выглядит приблизительно так:
If WorkSpace==xxx then WorkSpace=yyy
Или, в общем случае:
If
WorkSpace==LeftPattern then WorkSpace=RightField
Как забить изначальные данные в WorkSpace – вопрос
интересный. В данном выше коде smtp-авторизации в WorkSpace будет
содержаться адрес электронной почты получателя. Но для обучения можно создать
файл test.cf с
таким содержимым:
V10
STest
R xxx <TAB> yyy
(в первой строке мы указываем версию, в принципе, это не
обязательно. Во второй строке указываем названием раздела).
Теперь в командной строке вводим:
> sendmail -bt –C
test.cf
Вводим название раздела и изначальные данные WorkSpace:
Test xxx
Будет выведено такое:
Test Input: xxx
Test Returns: yyy
(Выход: Ctrl+D)
То есть, наши изначальные введенные данные (WorkSpace) совпали с шаблоном
«xxx», поэтому правило
вернуло результат «yyy».
Если бы ввели другие изначальные данные, было бы:
Test Input: xxxс
Test Returns: xxxс
Пояснение кода smtp-аунтентификации:
1. LOCAL_CONFIG Ksyslog syslog
Здесь связано с логированием
2. LOCAL_RULESETS SLocal_check_rcpt
Называем наш раздел Local_check_rcpt. По этому имени его
можно вызвать для тестирования через sendmail –bt.
Однако, не советую. Лучше использовать для тестирования либо отдельный файл,
либо через сообщения об ошибках (будет сказано в конце статьи).
3. # empty address?
R<> $#error $@ nouser $: "553 User address required"
R$@ $#error $@ nouser $: "553 User address required"
Смотрим что из себя представляет адрес получателя
электронной почты. Если там только угловые скобки или еще какая-то [хрень], то
выдаём сообщение об ошибке. Как именно работает эта строка, углубляться не
будем. Она почти стандартная.
4. #Добавляем адрес отправителя
R$* $: $1 $| $&f
Эта строка сложная и требует многих пояснений.
1) знак $* означает шаблон равный 0 или более токенов. Под
токеном подразумевается некое слово ограниченное специальными символами.
Например, xxx@yyy – два токена. По сути, одиночное
использование шаблона $* означает то же, что и «*» при поиске имён файлов.
А в данном случае, такой паттерн используется, чтобы в любом случае выполнилось
правое выражение. То есть, что-то вроде if TRUE then…
2) знак $: означает, что данное правило выполнится один раз.
У Sendmail есть заморочка, что правило должно работать некоторое
количество раз, эдакое зацикленное выражение. Рекомендую всегда использовать $:,
разве что вы знаете, что делаете.
3) В выражения $1, $2, $3 и т.д. записывается то, что было
найдено при использовании шаблона. То есть, при поиске на совпадение xxx.yyy.zzz:
R $-.$-.$- $1 $2 $3
($- означает строго один токен)
Мы имеем $1=xxx,
$2=yyy, $3=zzz
4) $| одна из тех команд, что используются часто, но
описания на них нет… Она представляет собой что-то вроде буфера обмена, чтобы
можно было какие-то данных сохранять и использовать в следующих командах.
Пример:
R $* $: $| asdf
R $| asdf zzz
В первой строке: мы в любом случае записываем в «буфер
обмена» четыре букы asdf
Во второй строке: смотрим, есть ли в буфере обмена четыре
буквы asdf. И если
есть, то в WorkSpace записываем zzz.
5) $&f
–адрес отправителя.
То есть, команда «R$* $:
$1 $| $&f» означает: отработать 1 раз; в WorkSpace записать
то, что есть ($1 – в нашем случае адрес получателя), а в буфер записать адрес
отправителя.
5. #Канонизируем адреса R$* $| $* $: $2 $| $>Parse0 $>3 $1
R$* $| $* $: $2 $| $>Parse0 $>3 $1
Это одна из тех строк, которые сложны для начального понимания.
Слева видно, что шаблон смотрит есть ли что-то в WorkSpace и в
буфере обмена. Справа же, с помощью $> идут вызовы других кусков
конфигурационного файла. В результате работы этих двух строк наши оба адреса
(получателя и отправителя) будут в каноническом виде: user<@domain.com.> (обратите внимание на точку в
конце имени домена!)
Надо сказать, что если один из адресов идёт без домена
(просто имя пользователя), то с ним никаких изменений не произойдёт.
6. #Ксли отправитель и
получатель локальные, отправляем их на проверку в CheckLocalAuth R$+<@$=w.> $| $+<@$=w.> $: $>CheckLocalAuth
Здесь, собственно мы и проверяем формат адресов на
совпадение с нашим доменом.
$=w выдаст наш домен.
$+ означает один и более токенов.
То есть, наше условие выглядит где-то так: if (WorkSpace==”serg<@MyDomainSendmailServer.com.>”)
and (Bufer==” anna<@MyDomainSendmailServer.com.>”)
then CALL CheckLocalAuth. А
CheckLocalAuth идёт ниже.
7. #Другие варианты
fqdn-адресов пропускаем (внеш-внеш, внутр-внеш, внеш-внутр) R$+<@$+> $| $+<@$+> $@ $1
Здесь уже мы не смотрим принадлежат ли адреса нашему домену
или нет. Лишь бы было похоже на адреса электронной почты (канонические).
Знак $@ (когда он в правой колонке) означает, что мы
прекратим работу этой подпрограммы. Не забываем, что весь тот код мы будет
встраивать. Вот таким образом, мы просто прервём выполнение наших действий, и
отдадим управление другим командам конфигурационного файла.
8. #Алиасы, MAILER-DAEMON и др.
лок. получатели без доменной части - в ту же проверку R$+ $| $+ $: $>CheckLocalAuth
То есть, бездоменные адреса электронной почты тоже отправим
на проверку в CheckLocalAuth
9. #Контрольная проверка - кто
там не охвачен нашими правилами: если сработает - покажешь,
подправим R$* $: $(syslog syslog:PROBLEM: $1 $) $1
Идёт запись в системный лог-файл.
10. SCheckLocalAuth
Вот, собственно и процедура по проверке на smtp-аутентификацию.
11. #Почту с самого
сервера пропускаем R$* $: $&{client_addr}
R127.0.0.1 $@OK
$&{client_addr} возвратит ip-адрес отправителя. И
запишется он в WorkSpace.
Следующей строкой сравнится WorkSpace с
адресом 127.0.0.1, и если они совпадут, то выполнится прерывание процедуры $@.
12. #Если авторизация имела
место - пропускаем R$* $: < $&{auth_authen} >
R< $+ > $@ OK
$&{auth_authen} запишет в WorkSpace информацию
про авторизацию.
И следующей строкой посмотрим есть ли в WorkSpace что-то (не пустота). Если
есть, значит, авторизация была, всё хорошо, и опять завершаем работу процедуры.
13. #Все остальное блокируем R$* $#error: $: 553 Sorry, you must use smtp-authentication. Please, contact to postmaster.
Если мы добрались сюда, значит, наш адрес не был 127.0.0.1 и
авторизации не было, поэтому выдаём сообщение об ошибке.
Debug (отладка) через сообщения об ошибках
Кстати, через $#error можно делать debug команд.
После подозрительной или не правильно работающей команды можно прописать:
R$* $| $* $#error: $: WorkSpace=$1 Buffer=$2
Дабы видеть содержимое WorkSpace и буфера. Эти ошибки можно
будет видеть либо через telnet либо через клиент электронной почты.
Дальнейшая доработка
Но вышеприведенный код тоже имеет недостатки! Пункт 6:
#Ксли
отправитель и получатель локальные, отправляем их на проверку в CheckLocalAuth
R$+<@$=w.> $| $+<@$=w.> $: $>CheckLocalAuth
R$+<@$=w.> $| $+<@$=w.> $: $>CheckLocalAuth
То есть, здесь идёт проверка в том случае, если спамер буде
рассылать письма из «засвеченного» адреса в локальную сеть (т.е. оба адреса
локальные)! А если спамер, как вначале статьи, захочет спамить во вне?
Поэтому, предлагаю следующий вариант:
#Ксли
отправитель и получатель локальные, отправляем их на проверку в CheckLocalAuth
R$* $| $+<@$=w.> $: $>CheckLocalAuth
R$* $| $+<@$=w.> $: $>CheckLocalAuth
То есть, независимо какой адрес получателя, мы всё равно
отправим на проверку.
Далее, в разделе CheckLocalAuth теоретически можно убрать проверку на ip. Просто удалить две строки, которые описаны в пункте 11. Но тогда служебные письма от сервера не будут доходить до к вашему второму служебному ящику. Либо как-то сервер настроить, чтобы и он проходил smtp-авротизацию.
Всё, теперь в любом случае, если кто-то захочет слать письмо
от вашего домена, ему необходимо будет ввести smtp-пароль к ящику.
Комментариев нет:
Отправить комментарий