На сервере, где находятся сайты различных пользователей, чаще всего предусмотрена возможность отправки сообщений через локальный почтовый сервер. В случае взлома одного из сайтов существует возможность рассылки спам-сообщений, что может привести к серьезным последствиям, таким, как занесение IP-адреса почтового сервера в листы.
Для того, чтобы предотвратить возможность дискредитации почтового сервера, необходимо ограничить максимальное количество исходящих сообщений, которые каждый пользователь сможет отправлять в определенный промежуток времени.
Проблема не является абсолютно тривиальной, и задачей данной статьи является демонстрация готового решения, которое может применяться в продакшене.
Исходные данные: ОС Debian 8 («Jessie»), почтовый сервер Postfix.
Установка и настройка пакета postfwd
Установим пакет postfwd при помощи apt:
apt-get install postfwd
Пакет не имеет файла конфигурации и не запускается по умолчанию. Создадим файл конфигурации /etc/postfix/postfwd.cf и добавим правило (отправка не более 50 сообщений в час для одного пользователя):
id=R001; action=rcpt(sender/50/3600/REJECT limit of 50 recipients per hour for sender $$sender exceeded)
Подробнее о конфигурации postfwd можно прочитать в документации на сайте проекта.
Отредактируем файл /etc/default/postfwd:
# Разрешить запуск демона STARTUP=1 # Путь к файлу, где содержатся правила CONF=/etc/postfix/postfwd.cf # IP адрес, на котором демон будет слушать входящие сообщения INET=127.0.0.1 # Порт, на котором демон будет слушать входящие сообщения PORT=10040 # Пользователь, от которого работает демон RUNAS="nobody" # Аргументы, которые передаются демону при старте ARGS="--summary=600 --cache=600 --cache-rdomain-only --cache-no-size"
Перезапустим сервис postfwd:
service postfwd restart
И проверим, что всё работает как надо:
srv1:~# tail /var/log/mail.log Jun 9 14:14:18 srv1 postfwd2/master[37242]: postfwd2 1.35 starting Jun 9 14:14:18 srv1 postfwd2/master[37244]: Started cache at pid 37245 Jun 9 14:14:18 srv1 postfwd2/master[37244]: Started server at pid 37246 Jun 9 14:14:18 srv1 postfwd2/cache[37245]: ready for input Jun 9 14:14:18 srv1 postfwd2/policy[37246]: ready for input
Интеграция postfix и postfwd
Для того, чтобы выполнить интеграцию почтового сервера Postfix и службы postfwd, необходимо изменить конфигурационный файл /etc/postfix/main.cf, добавив в него следующие параметры:
# Подключаем наш policy service - postfwd и разрешаем отправку только авторизированным пользователям smtpd_recipient_restrictions = check_policy_service inet:127.0.0.1:10040, permit_sasl_authenticated, reject_unauth_destination # Подключаем наш policy service - postfwd smtpd_end_of_data_restrictions = check_policy_service inet:127.0.0.1:10040
Подключение posftwd должно осуществляться в начале, это связанно с особенностью интерпретации параметров почтовым сервером Postfix. В случае, если в конфигурационном файле уже заданы параметры smtpd_recipient_restrictions и smtpd_end_of_data_restrictions, необходимо изменить их таким образом, чтобы check_policy_service inet:127.0.0.1:10040 и permit_sasl_authenticated размещались в начале.
Перезагружаем конфигурацию:
srv1:~# postfix reload postfix/postfix-script: refreshing the Postfix mail system
После перезагрузки postfwd начинает свою работу и периодически выводит статистику в почтовый журнал (/var/log/mail.log):
srv1:~# tail /var/log/mail.log | grep postfwd Jun 9 14:24:18 srv1 postfwd2/master[37244]: [STATS] postfwd2::policy 1.35: 1 requests since 0 days, 00:09:59 hours Jun 9 14:24:18 srv1 postfwd2/master[37244]: [STATS] Requests: 0.10/min last, 0.10/min overall, 0.10/min top Jun 9 14:24:18 srv1 postfwd2/master[37244]: [STATS] Dnsstats: 0.00/min last, 0.00/min overall, 0.00/min top Jun 9 14:24:18 srv1 postfwd2/master[37244]: [STATS] Hitrates: 0.0% ruleset, 0.0% parent, 0.0% child, 0.0% rates Jun 9 14:24:18 srv1 postfwd2/master[37244]: [STATS] Timeouts: 0.0% (0 of 0 dns queries) Jun 9 14:24:18 srv1 postfwd2/master[37244]: [STATS] 1 matches for id: R001
Теперь всем пользователям, отправляющим почтовые сообщения через SMTP сервер, будут установлены лимиты, соответствующие заданным в postfwd правилам (в нашем случае задано только одно правило). Однако все сообщения, отправляемые через /usr/sbin/sendmail, не будут подвергаться фильтрации, поскольку Postfix отправляет их напрямую в очередь, минуя postfwd.
Настройка «заглушки» для /usr/sbin/sendmail
Наиболее простым и эффективным решением является использование «заглушки» для скрипта /usr/sbin/sendmail, которая отправляла бы всю корреспонденцию через SMTP сервер с авторизацией. Соответственно, необходимо также запретить отправку сообщений через SMTP неавторизированным локальным пользователям. Проверяем, что в конфигурационном файле /etc/default/postfwd отсутствет параметр permit_mynetworks в smtpd_recipient_restrictions — в этом случае авторизация потребуется даже локальным пользователям.
Для того, чтобы применить решение с «заглушкой» на практике, необходимо создать на почтовом сервере ящики, которые будут соответствовать пользователям, а также ящик «по умолчанию», например:
- site1@myserver.org
- site2@myserver.org
- default@myserver.org
Необходимо задать один пароль для всех ящиков (site1, site2 и т.д.), и другой пароль для default@myserver.org. Сохранять письма в эти ящики не нужно, так что можно настроить форвардинг в /dev/null.
Подобная конфигурация разрешает отправку до 50 писем в час всем перечисленным пользователям, и отправку 50 сообщений «на всех» для тех пользователей, у которых нет отдельного аккаунта.
«Заглушка» будет работать следующим образом:
- Определять имя пользователя, который запустил наш скрипт
- Попытаться авторизироваться на почтовом сервере, используя полученное в п. 1 имя пользователя
- В случае ошибки авторзироваться как default
- Пересылать письмо
Код написан на Perl и требует установки дополнительных модулей, установим их через CPAN:
srv1:~# cpan Net::SMTP_auth Email::Address
Создадим дирректорию, в которой мы будем хранить скрипт (например, /usr/local/bin/private), а также непривилегированного пользователя, который станет «владельцем» дирректории и скрипта:
srv1:~# mkdir /usr/local/bin/private srv1:~# useradd sendmail
Добавим в созданную директорию наш скрипт-«заглушку» (/usr/local/bin/private/sendmail.pl), заменив переменные $smtp_password, $smtp_default_password и $server соответственно на пароль пользовательских ящиков, пароль ящика «по умолчанию» и адрес вашего хоста, на котором созданы ящики:
#!/usr/bin/perl use strict; use warnings; use Net::SMTP_auth; use Email::Address; my $user = getpwuid( $< ); my $smtp_password = 'password'; my $smtp_default_password = 'password'; my $server = 'srv1.re-hash.org'; my $input = ''; my $to_string = ''; foreach my $line ( <STDIN> ) { $input .= $line; if ($line =~ /^To:/) { $to_string = $line; } } my @addrs = Email::Address->parse($to_string); if (0+@addrs eq 0) { die "No recipients"; } my $rec = $addrs[0]; $rec =~ s/\@/\\@/; my $smtp = Net::SMTP_auth->new('127.0.0.1', Port => 25, Timeout => 10, Debug => 0); die "Could not connect to SMTP server!\n" unless $smtp; if (!$smtp->auth('PLAIN', $user.'@'.$server, $smtp_password)) { $smtp->auth('PLAIN', 'default@'.$server, $smtp_default_password) or die "Auth failed!\n"; } $smtp->mail($user.'\@'.$server); $smtp->to($rec); $smtp->data(); $smtp->datasend($input); $smtp->dataend(); $smtp->quit;
Установим права на дирректорию и скрипт. Необходимо сделать так, чтобы пользователи могли выполнять скрипт, но не читать его:
srv1:~# chown -R sendmail:sendmail /usr/local/bin/private srv1:~# chmod -R 4711 /usr/local/bin/private
Необходимо не забыть переименовать файл /usr/sbin/sendmail, а также снять с него права на выполнение.
В принципе, теперь вместо /usr/sbin/sendmail можно использовать путь /usr/local/bin/private/sendmail.pl (или сразу сохранить скрипт как /usr/sbin/sendmail), но мне захотелось сделать иначе. Поэтому я решил написать еще один враппер (да, враппер поверх враппера), который заменит /usr/sbin/sendmail. Код враппера (wrapper.c) написан на C и выглядит следующим образом:
/* wrapper.c */ #define REAL_PATH "/usr/local/bin/private/sendmail.pl" main(ac, av) char **av; { execv(REAL_PATH, av); }
Выполним компиляцию этого файла, скопируем его в /usr/sbin и выставим соответствующие права:
srv1:~# cc -o sendmail wrapper.c srv1:~# cp -a ./sendmail /usr/sbin/sendmail srv1:~# chown -R sendmail:sendmail /usr/sbin/sendmail srv1:~# chmod -R 4711 /usr/sbin/sendmail
После выполнения перечисленных выше действий все сайты должны отправлять почтовые сообщения точно так же, как и раньше, но к отправляемым сообщениям начнут применяться лимиты и правила, заданные в конфигурации postfwd.
Исходный код враппера доступен в GitHub: github.com/xtremespb/sendmail-wrapper.
Буду рад замечаниям и предложениям по совершенствованию механизма лимитирования в комментариях.
ссылка на оригинал статьи http://habrahabr.ru/post/259937/
Добавить комментарий