Для того, чтобы снизить риск попадания исходящей почты в спам, используется популярная связка SPF, DKIM и DMARC. Данные технологии направлены на борьбу с поддельными почтовыми сообщениями. Рассмотрим практическую реализацию этих технологий на почтовом сервере, сконфигурированном в статье Postfix Dovecot LDAP.
Для лучшего понимания, обратимся к примеру отправки почтового сообщения через утилиту telnet.
Все, что находится до команды DATA, является конвертом сообщения. С этой информацией работает SPF. То, что находится после команды DATA, является заголовком сообщения, с этой информацией работает DKIM. DMARC является результирующей политикой, определяющей дальнейшую судьбу сообщения, опираясь на результаты SPF и DKIM проверок. Результаты SPF, DKIM и DMARC проверок записываются в заголовок сообщения, и в дальнейшем могут быть использованы антиспам фильтрами.
Установка и настройка postfix-policyd-spf-python
Для того, чтобы Postfix мог проводить SPF проверки для входящей почты нужно установить пакет postfix-policyd-spf-python
# apt install postfix-policyd-spf-python
В конец файла master.cf нужно добавить следующие строки
# nano /etc/postfix/master.cf . . . policyd-spf unix - n n - 0 spawn user=policyd-spf argv=/usr/bin/policyd-spf
Добавим поддержку postfix-policyd-spf-python в Postfix
# nano /etc/postfix/main.cf . . . smtpd_relay_restrictions = permit_mynetworks permit_sasl_authenticated defer_unauth_destination check_policy_service unix:private/policyd-spf . . . policyd-spf_time_limit = 3600
Здесь важна последовательность. Параметр check_policy_service unix:private/policyd-spf активирует SPF проверку в Postfix. Он должен быть последним в списке ограничении smtpd_relay_restrictions. Параметр policyd-spf_time_limit = 3600 может находится в любом месте, он определяет временной предел проверки сообщения.
Откроем конфигурационный файл postfix-policyd-spf-python и добавим в конец это файла следующие строки
# nano /etc/postfix-policyd-spf-python/policyd-spf.conf . . . Header_Type = AR Authserv_Id = mail.4skill.ru
Параметр Header_Type указывает метод документирования результатов SPF проверки в проверяемых сообщениях. По умолчанию используется метод SPF. Смена метода SPF на AR используется для совместимости с OpenDMARC. Параметр Authserv_Id определяет имя идентификатора, которое используется при создании поля результатов проверки в заголовке сообщения. Обычно в качестве идентификатора указывается полное доменное имя сервера, на котором производится проверка. Более подробное описание всех параметров можно найти на странице Ubuntu manuals. Детальное описание настройки SPF изложено в статье Postfix настройка SPF.
Перезапустим Postfix
# postfix reload
Теперь Postfix будет производить SPF проверку для всех входящих писем. Осталось добавить SPF запись для домена 4skill.ru. Перейдем в консоль своего DNS провайдера и добавим туда запись типа TXT для домена 4skill.ru.
@ TXT v=spf1 mx ~all
В начале указывается версия SPF записи (v=spf1), затем разрешения. В данном случае осуществлять отправку почты от имени домена 4skill.ru могут хосты, указанные в MX записи для данного домена (mx). Почта от иных хостов будет принята с пометкой о неудачной проверке(∼all). Более подробное описание синтаксиса и примеры SPF записей можно найти на странице SPF Record Syntax, или в начале статьи Postfix настройка SPF.
Установка и настройка OpenDKIM
Для того, чтобы Postfix мог проводить DKIM проверки для входящей почты, нужно установить пакеты OpenDKIM и OpenDKIM-Tools. Последний нужен для генерации ключей.
# apt install opendkim opendkim-tools
После установки данных пакетов, заменим оригинальный конфигурационный файл OpenDKIM на следующий
# nano /etc/opendkim.conf AutoRestart yes AutoRestartRate 10/1h Canonicalization relaxed/relaxed ExternalIgnoreList refile:/etc/opendkim/trusted_hosts InternalHosts refile:/etc/opendkim/trusted_hosts KeyTable refile:/etc/opendkim/key_table SigningTable refile:/etc/opendkim/signing_table On-BadSignature accept ReportAddress noreply-dkim@4skill.ru SendReports yes SignHeaders From,To,Subject,Date,Message-ID Syslog yes SyslogSuccess yes #LogWhy yes UMask 002
- AutoRestart — автоматический перезапуск сервиса в случае падения.
- AutoRestartRate — допустимая частота падений сервиса. В данном случае не более 10 раз за 1 час.
- Canonicalization — канонизация для заголовка/тела сообщения. Подробнее об это тут.
- ExternalIgnoreList — список внешних хостов, которые могут производить пересылку почты от имени подписываемого домена без аутентификации.
- InternalHosts — список внутренних хостов, чья исходящая почта не должна проверяться, но должна быть подписана.
- KeyTable — список ключей, используемых для подписи.
- SigningTable — список доменов, сопряженных с ключами из KeyTable.
- On-BadSignature — что делать с письмом в случае неудачной проверки. Возможны варианты:
∘ accept — пропустить(по умолчанию);
∘ discard — отбросить сообщение без уведомления;
∘ quarantine — поместить сообщение в спам;
∘ reject — отбросить сообщение;
∘ tempfail — выдать сообщение об ошибке. - ReportAddress — адрес, от имени которого будет происходить рассылка отчетов о неудачных проверках.
- SendReports — включение рассылки отчетов о неудачных проверках.
- SignHeaders — набор полей заголовка сообщения, которые будут включены в подпись.
- Syslog — запись логов в syslog.
- SyslogSuccess — включение в лог информации об успешных подписях и проверках.
- LogWhy — включение более детального логирования.
- UMask — маска прав для Socet файла.
Подробное описание всех параметров можно найти на странице opendkim.conf.
Создадим каталок для хранения ключей
# mkdir -p /etc/opendkim/keys/4skill.ru
Добавим ключи для домена 4skill.ru
# opendkim-genkey -D /etc/opendkim/keys/4skill.ru -d 4skill.ru -s mail
Ключ -D определяет каталог для записи ключей. Ключ -d указывает название домена. Ключ -s указывает название селектора. Селектор может быть произвольным. Обычно селектор отражает название сервиса, дату создания ключа, или битность ключа. В данном случае это название сервиса.
Пользователь, от имени которого работает сервис OpenDKIM, должен иметь доступ к закрытому ключу
# chown opendkim /etc/opendkim/keys/4skill.ru/*.private
Открытый ключ находится в файле с расширением .txt
# cat /etc/opendkim/keys/4skill.ru/*.txt mail._domainkey IN TXT ( "v=DKIM1; k=rsa; " "p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDMtyLiYLXF0ywByDzfnQmdI+OMBsr6dg0OfXnejQtKwwCKmxLdxdk7dXXca7ZaO10b35deSX2XQuCuKp0ZeVsRAQsEu4dAYrJ/5Km7Rh3V45uLv1w7ksky128u6oiqllL5iVg+MWWQYtbedO7hT/Rod+aXb7DV3NjNAIl53ZdPtQIDAQAB" ) ; ----- DKIM key mail for 4skill.ru
Добавим его на DNS сервер своего провайдера в виде TXT записи
mail._domainkey.4skill.ru TXT v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDMtyLiYLXF0ywByDzfnQmdI+OMBsr6dg0OfXnejQtKwwCKmxLdxdk7dXXca7ZaO10b35deSX2XQuCuKp0ZeVsRAQsEu4dAYrJ/5Km7Rh3V45uLv1w7ksky128u6oiqllL5iVg+MWWQYtbedO7hT/Rod+aXb7DV3NjNAIl53ZdPtQIDAQAB
Создадим файл, определяющий от кого подписывать почту
# nano /etc/opendkim/trusted_hosts ::1 127.0.0.1
Даже если явно не указывать ::1 или 127.0.0.1, почта сформированная почтовыми клиентами пользователей, прошедших аутентификацию на сервере будет подписана. Явное указание адреса петлевого интерфейса дает возможность подписи почты, сформированной утилитой telnet на почтовом сервере(# telnet localhost 25). На практике в данный файл записываются адреса серверов, использующих Postfix в качестве сервера пересылки(relay), с целью подписи транзитных сообщений.
Создадим файл, определяющий список закрытых ключей
# nano /etc/opendkim/key_table mail._domainkey.4skill.ru 4skill.ru:mail:/etc/opendkim/keys/4skill.ru/mail.private
Каждый ключ прописывается отдельной строкой и имеет формат
<название ключа> <название домена>:<название селектора>:<путь к закрытому ключу>
Создадим файл, сопоставляющий закрытый ключ с именем домена
# nano /etc/opendkim/signing_table *@4skill.ru mail._domainkey.4skill.ru
Формат записи следующий
<название домена> <название ключа из key_table>
Укажем SOCKET для подключения к OpenDKIM
# nano /etc/default/opendkim
Закоментируем строку
#SOCKET="local:/var/run/opendkim/opendkim.sock"
Раскоментируем строку
SOCKET="inet:12345@localhost"
Укажем Postfix как подключаться к OpenDKIM. Для этого добавим к конец main.cf следующие строки
# nano /etc/postfix/main.cf . . . smtpd_milters = inet:localhost:12345 non_smtpd_milters = $smtpd_milters
Перезапустим OpenDKIM
# service opendkim restart
Перезапустим Postfix
# postfix reload
Более детальная настройка OpenDKIM описана в статье Postfix OpenDKIM.
Установка и настройка OpenDMARC
Для того, чтобы Postfix мог проводить DMARC проверки для входящей почты, нужно установить пакет OpenDMARC
# apt install opendmarc
Заменим оригинальный конфигурационный файл OpenDMARC на следующий
# nano /etc/opendmarc.conf AuthservID mail.4skill.ru AutoRestart yes AutoRestartRate 10/1h FailureReports yes FailureReportsSentBy noreply-dmarc@4skill.ru HistoryFile /var/run/opendmarc/opendmarc.dat IgnoreHosts /etc/opendkim/trusted_hosts IgnoreAuthenticatedClients yes RejectFailures no Syslog yes UMask 002
- Authserv_Id — имя идентификатора, которое используется при создании поля результатов проверки в заголовке сообщения. Обычно в качестве идентификатора указывается полное доменное имя сервера, на котором производится проверка.
- AutoRestart — автоматический перезапуск сервиса в случае падения.
- AutoRestartRate — допустимая частота падений сервиса. В данном случае не более 10 раз за 1 час.
- FailureReports — включение рассылки отчетов о неудачных проверках.
- FailureReportsSentBy — адрес, от имени которого будет происходить рассылка отчетов о неудачных проверках.
- HistoryFile — расположение файла, в который записывается информация, используемая для создания сводных отчетов.
- IgnoreHosts — расположение файла, содержащего список имен хостов, IP адресов и CIDR выражений, которые нужно исключить из проверки.
- IgnoreAuthenticatedClients — исключение из проверки аутентифицированных клиентов.
- RejectFailures — действие в случае неудачной проверки. Возможные варианты:
∘ yes — отклонить письмо;
∘ no — пропустить письмо и добавить в заголовок сообщения поле с результатами проверки (поведение по умолчанию). - Syslog — запись логов в syslog.
- UMask — маска прав для Socet файла.
Подробное описание всех параметров можно найти на странице opendmarc.conf.
Укажем SOCKET для подключения к OpenDMARC, для этого добавим следующую строку в файл /etc/default/opendmarc
# echo 'SOCKET="inet:12346@localhost"' >> /etc/default/opendmarc
Укажем Postfix как подключаться к OpenDMARC. Для этого отредактируем файл /etc/postfix/main.cf
# nano /etc/postfix/main.cf
Заменим строку (сочетание клавиш Alt+R)
smtpd_milters = inet:localhost:12345
На
smtpd_milters = inet:localhost:12345 inet:localhost:12346
Здесь важна последовательность. В начале указывается SOCET для подключения к OpenDKIM, затем к OpenDMARC.
Перезапустим службу OpenDMARC
# service opendmarc restart
Перезапустим службу Postfix
# postfix reload
Еще одна полезная функция OpenDMARC это рассылка сводных отчетов. Сводный отчет содержит в себе статистику принятых писем от определенных доменов, с процентным соотношением удачных и неудачных проверок SPF, DKIM и DMARC. Изначально статистика по входящей почте записывается в файл, определенный параметром HistoryFile. Затем скриптом opendmarc-import статистика импортируется в базу данных MySQL. Далее используется скрипт opendmarc-reports, который достает статистику из базу данных MySQL, формирует письмо с прикрепленным отчетом и осуществляет отправку письма. Заключительным этапом является запуск скрипта opendmarc-expire, который очищает базу данных MySQL от устаревших записей.
Установка и настройка MySQL
Для установки MySQL выполним команду
# apt install mysql-server
В процессе установки появится окно с запросом указания пароля для пользователя root. Это не системный пользователь Linux, а одноименный корневой администратор базы данных MySQL. На данном этапе можно ничего не указывать и оставить поле пустым, так как в дальнейшем пароль будет определен конфигурационным скриптом для настройки MySQL
После установки базы данных MySQL, нужно запустить конфигурационный скрипт mysql_secure_installation
# mysql_secure_installation Securing the MySQL server deployment. Connecting to MySQL using a blank password. VALIDATE PASSWORD PLUGIN can be used to test passwords and improve security. It checks the strength of password and allows the users to set only those passwords which are secure enough. Would you like to setup VALIDATE PASSWORD plugin? Press y|Y for Yes, any other key for No: n Please set the password for root here. New password: Re-enter new password: By default, a MySQL installation has an anonymous user, allowing anyone to log into MySQL without having to have a user account created for them. This is intended only for testing, and to make the installation go a bit smoother. You should remove them before moving into a production environment. Remove anonymous users? (Press y|Y for Yes, any other key for No) : y Success. Normally, root should only be allowed to connect from 'localhost'. This ensures that someone cannot guess at the root password from the network. Disallow root login remotely? (Press y|Y for Yes, any other key for No) : y Success. By default, MySQL comes with a database named 'test' that anyone can access. This is also intended only for testing, and should be removed before moving into a production environment. Remove test database and access to it? (Press y|Y for Yes, any other key for No) : y - Dropping test database... Success. - Removing privileges on test database... Success. Reloading the privilege tables will ensure that all changes made so far will take effect immediately. Reload privilege tables now? (Press y|Y for Yes, any other key for No) : y Success. All done!
В начале предлагается использовать плагин проверки сложности пароля. Далее указывается пароль для пользователя root базы данных MySQL. Затем предлагается удалить анонимного пользователя. Потом предлагается выключить возможность удаленного подключения пользователя root к базе данных MySQL. После чего предлагается удалить тестовую базу. В заключении предлагается обновить таблицы прав пользователей.
Далее нужно отключить режимы STRICT_TRANS_TABLES, NO_ZERO_IN_DATE и NO_ZERO_DATE. Если этого не сделать, то при импорте схемы OpenDMARC вылетит ошибка
ERROR 1067 (42000) at line 20: Invalid default value for 'lastsent'
Для отключения выше указанных режимов нужно добавить в файл /etc/mysql/my.cnf следующие строки
# nano /etc/mysql/my.cnf . . . [mysqld] sql-mode = ONLY_FULL_GROUP_BY,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION
и перезапустить службу MySQL
# service mysql restart
В файле схемы нужно раскоментировать две последние строки
# nano /usr/share/doc/opendmarc/schema.mysql . . . CREATE USER 'opendmarc'@'localhost' IDENTIFIED BY 'changeme'; GRANT ALL ON opendmarc.* to 'opendmarc'@'localhost';
Первая команда создаст пользователя opendmarc с паролем changeme. Вторая команда назначит все доступные привилегии пользователю opendmarc на базу opendmarc.
Теперь можно импортировать схему OpenDMARC в MySQL
# mysql -u root -p < /usr/share/doc/opendmarc/schema.mysql Enter password:
При выполнении данной команды нужно указать пароль пользователя root базы данных MySQL.
Далее отредактируем скрипт /usr/sbin/opendmarc-reports
# nano /usr/sbin/opendmarc-reports
Заменим строку (сочетание клавиш Alt+R)
$answer = ${${*$smtp}{'net_cmd_resp'}}[1];
На
$answer = ${${*$smtp}{'net_cmd_resp'}}[1] || $smtp->message() || 'unknown error';
Данная замена нужна для предотвращения ошибки #134.
Use of uninitialized value $answer in scalar chomp at /usr/sbin/opendmarc-reports line 938. Use of uninitialized value $answer in concatenation (.) or string at /usr/sbin/opendmarc-reports line 939.
Далее нужно создать связующий скрипт
# nano /etc/cron.daily/opendmarc-report #!/bin/bash DB_SERVER='localhost' # Адрес MySQL сервера DB_USER='opendmarc' # Пользователь для подключения к базе данных DB_PASS='changeme' # Пароль пользователя для подключения к базе данных DB_NAME='opendmarc' # Имя базы данных WORK_DIR='/var/run/opendmarc' # Директория, в которую записывается HistoryFile REPORT_EMAIL='noreply-dmarc@4skill.ru' # Адрес, от имени которого происходит рассылка сводных отчетов REPORT_ORG='4skill.ru' # Название домена, от имени которого происходит рассылка сводных отчетов mv ${WORK_DIR}/opendmarc.dat ${WORK_DIR}/opendmarc_import.dat -f touch ${WORK_DIR}/opendmarc.dat chown opendmarc:opendmarc ${WORK_DIR}/opendmarc.dat /usr/sbin/opendmarc-import --dbhost=${DB_SERVER} --dbuser=${DB_USER} --dbpasswd=${DB_PASS} --dbname=${DB_NAME} --verbose < ${WORK_DIR}/opendmarc_import.dat /usr/sbin/opendmarc-reports --dbhost=${DB_SERVER} --dbuser=${DB_USER} --dbpasswd=${DB_PASS} --dbname=${DB_NAME} --verbose --interval=86400 --report-email=${REPORT_EMAIL} --report-org=${REPORT_ORG} /usr/sbin/opendmarc-expire --dbhost=${DB_SERVER} --dbuser=${DB_USER} --dbpasswd=${DB_PASS} --dbname=${DB_NAME} --verbose
Сделаем скрипт исполняемым
# chmod +x /etc/cron.daily/opendmarc-report
Идея скрипта взята с сайта njae.me.uk. Скрипт будет выполняться раз в сутки.
Заключительным этапом будет добавление DMARC записи для домена 4skill.ru. Для этого в DNS оснастке своего провайдера нужно добавить TXT запись следующего вида
_dmarc.4skill.ru TXT v=DMARC1; p=none; rua=mailto:dmarc@4skill.ru; ruf=mailto:dmarc@4skill.ru
- v - версия записи.
- p - политика, может иметь значения:
∘ none - не принимать никаких действий;
∘ quarantine - отправить сообщение в спам;
∘ reject - не принимать сообщение. - rua - адрес для получения сводных отчетов.
- ruf - адрес для получения отчетов о неудачных проверках.
Описание всех доступных параметров DMARC записи и примеры можно найти на странице help.mail.ru.
В первое время лучше использоваться политику none, чтобы исключить потерю легитимной исходящей почты и изучить сводные отчеты DMARC, полученные от других почтовых систем. Далее можно изменить политику на более агрессивную, либо оставить none, в случае использования антиспам фильтров. Как правило современные антиспам системы используют SPF, DKIM и DMARC заголовки в своих проверках, что обеспечивает высокую вероятность попадания поддельной почты в спам. Сводный отчет представляет из себя файл с расширением .xml. Для его просмотра можно использовать XML to Human Converter.
Чтобы убедиться что все вышло, и исходящая почта проходит SPF, DKIM и DMARC проверки, можно отправить тестовое письмо на сторонний почтовый сервер, поддерживающий данные типы проверок, и посмотреть на нем оригинал письма. На примере gmail.com это выглядит следующим образом, нужно открыть отправленное письмо, и в правой части экрана нажать на кнопку, изображенную на картинке ниже
Далее из всплывающего меню выбрать "Показать оригинал". В верхней части открывшегося окна буду представлены результаты проверок
Также можно воспользоваться онлайн сервисом mail-tester.com.
вроде все настроил по туториалу, но когда смотрю на mail.log то получаю ошибку что порт 12346 отказал в дотсупе:
warning: connect to Milter service inet:localhost:12346: Connection refused
что это вообще значит,milter добвавлен в main.cf после dkim записи, так что должно работать, даже добавил запись сокета в конфиг opendmarc
На порту 12346 должен работать OpenDMARK сервис.
Это указывается в /etc/default/opendmarc
В /etc/postfix/main.cf должно быть
Сервис OpenDMARK должен быть запущен
И слушать указанный выше порт
Не приходит рассылка сводных отчетов
От кого? Кому? Что в логе?
Нашел опечатку в ТХТ записи _dmarc, завтра посмотрю придет или нет, если что напишу.
Выполняю скрипт в ручную, отчет на почту не пришел, в логах тоже вроде нет ошибок. А какой именно лог смотреть ?
opendmarc-reports: sent report for subscribe-ascon.ru to dmarc_report@ascon.ru (2.0.0 Ok: queued as 08B6D424609)
opendmarc-reports: sent report for gazprombank.ru to postgarbage@bb.gazprombank.ru (2.0.0 Ok: queued as 1EE9842460E)
opendmarc-reports: sent report for tutu.ru to mail-admins@tutu.ru (2.0.0 Ok: queued as 3CDDE424613)
opendmarc-reports: sent report for drive2.ru to dmarc-report@drive2.ru (2.0.0 Ok: queued as 8D440424615)
opendmarc-reports: sent report for eisinform.ru to reply@eisinform.ru (2.0.0 Ok: queued as BF7A942460E)
opendmarc-reports: terminating at Thu Sep 20 09:49:19 2018
opendmarc-expire: started at Thu Sep 20 09:49:19 2018
opendmarc-expire: connected to database
opendmarc-expire: expiring messages older than 180 day(s)
opendmarc-expire: no rows deleted
opendmarc-expire: expiring signatures on expired messages (id < 1)
opendmarc-expire: no rows deleted
opendmarc-expire: expiring request data older than 180 days
opendmarc-expire: no rows deleted
opendmarc-expire: terminating at Thu Sep 20 09:49:19 2018
вот что в конце
Судя по логу, все исправно работает. Ваш почтовый сервер рассылает отчеты для доменов адресантов. Что у Вас конкретно не работает?
Все норм, спасибо!