Как мы реализовали DKIM в «Mail.Ru для бизнеса»

в 9:20, , рубрики: Блог компании Mail.Ru Group, домены

Как мы реализовали DKIM в «Mail.Ru для бизнеса»

Недавно на Хабре уже была статья о том, как «Mail.Ru для бизнеса» становится лучше благодаря вашим комментариям: мы рассказывали, как реализовывали ваши пожелания. Сегодня я хочу остановиться на одной из воплощенных хотелок — возможности настройки собственной DKIM-подписи. Для нас она была одним из приоритетов: настройка DKIM позволяет владельцам доменов верифицировать отправителя того или иного письма. В этом посте я расскажу о том, как мы внедряли эту возможность, и о том, как настроить DKIM-подпись для своего домена.

Немного о том, зачем нужна технология DKIM

Wikipedia напоминает нам, что «технология DomainKeys Identified Mail (DKIM) объединяет несколько существующих методов антифишинга и антиспама с целью повышения качества классификации и идентификации легитимной электронной почты. Вместо традиционного IP-адреса для определения отправителя сообщения DKIM добавляет в него цифровую подпись, связанную с именем домена организации. Подпись автоматически проверяется на стороне получателя».

То есть всякий раз, когда пользователь отправляет письмо, наш сервер добавляет в него специальный заголовок с цифровой DKIM-подписью. При генерации подписи используется секретный ключ (для каждого домена свой) и выдержки из письма. Этот заголовок позволяет серверу-получателю удостовериться, что письмо действительно отправлено владельцем этого домена.

DKIM-подписи — один из факторов, позволяющих нашей, как, впрочем, и другим антиспам-системам отделять письма благонадежных отправителей от подделок. Например, DKIM обеспечивает работу технологии DMARC, о которой мы уже писали раньше. DMARC позволяет распознать и отфильтровать спам и фишинговые письма, замаскированные под сообщения от известных сервисов.

Кроме того, DKIM-подпись нужна для работы технологии FBL (благодаря FBL отправители рассылок могут собирать фидбек о состоянии базы клиентов и их лояльности, а также проверять, как подписчики реагируют на рассылки, и дорабатывать содержание писем).

В общем, настройка DKIM-подписей — вещь, безусловно, полезная и необходимая, так что вопроса «Делать или нет?» не возникало. Мы взялись за работу. Дальше мы будем подробно рассказывать о том, как мы реализовывали данный функционал в «Mail.Ru для бизнеса». Если не хотите деталей, советуем сразу идти в пункт «Как мне настроить DKIM?».

Как настройка DKIM-подписей появилась в «Mail.Ru для бизнеса»

Для отправки писем у нас используется очень распространенный агент передачи почтовых сообщений (MTA, Mail Transfer Agent) exim4. Он уже имеет встроенные средства для размещения DKIM-подписи в исходящих сообщениях. До недавнего времени мы все свои письма именно таким образом и подписывали. Однако проблема в том, что количество подключенных бизнес-доменов постоянно растет, и у каждого домена свой секретный ключ. Если раньше достаточно было единожды разложить ключи по всем серверам и указать exim’у путь к этим ключам, то теперь такое решение уже никуда не годится. Проблему можно было бы решить, если «научить» exim обращаться за ключом в централизованную базу данных. Так мы и решили поступить.

Сказано — сделано. Многие специалисты ценят exim за богатые возможности настройки. При помощи встроенного языка конфигурации можно легко научить exim обращаться за данными в «плоские» файлы, берклеевские базы данных и даже выполнять SQL-запросы в реляционные БД, таких как MySQL. Для нужд почтового сервера среднестатистической компании возможностей конфигурирования хватит за глаза. Если же требуется нечто большее, то в exim’е имеются возможности для написания собственного lookup-модуля, который можно использовать в конфигурациях наравне со встроенными возможностями.

Для запроса ключа из БД создается небольшой вспомогательный lookup-модуль. Он занимается установкой подключения к базе данных, авторизацией, поиском нужного шарда, реплики, дешифрацией полученных данных и т. д., предоставляя наружу простой интерфейс словаря. Ниже вкратце описан сам процесс создания модуля.

Сначала в дерево исходников добавляем файл src/lookups/dkim.c (не забываем добавить его в систему сборки по аналогии с уже существующими модулями). В нём находятся исходники нашего модуля.

Далее описываем в файле структуру новых lookup-запросов:

/* Какой приватный ключ использовать для подписи */
static lookup_info _lookup_info1 = {
  US"dkim_privkey",      /* lookup name */
  lookup_querystyle,
  _open_connection,      /* open function */
  NULL,                          /* no check function */
  _get_priv_key,             /* find function */
  _close_connection,      /* close function */
  _tidy_cache,                /* tidy function */
  NULL,                          /* no quoting function */
  NULL                           /* no version function */
};
/* Какой селектор указывать в подписи */
static lookup_info _lookup_info2 = {
  US"dkim_selector",        /* lookup name */
  …
}; 
/* Какой домен указывать в подписи */
static lookup_info _lookup_info3 = {
  US"dkim_domain",        /* lookup name */
  …
};

static lookup_info *_lookup_list[] = { &_lookup_info1, &_lookup_info2, &_lookup_info3 };
lookup_module_info dkim_lookup_module_info = { LOOKUP_MODULE_INFO_MAGIC, _lookup_list, 3 };

Коллбэк-функции в структурах имеют четкий интерфейс и предназначение. Подробности реализации этих функций выходят за рамки статьи. Замечу только, что документации и примеров хватает за глаза, чтобы во всем этом разобраться.

После реализации внутренностей модуля остается его зарегистрировать. Заходим в файл src/drtables.c и добавляем описание модуля (куда конкретно вставлять строки, понятно из контекста — по аналогии со стандартным кодом):

extern lookup_module_info dkim_lookup_module_i
void init_lookup_list(void)
{
…
  addlookupmodule(NULL, &dkim_lookup_module_info);
...
}

Вот как выглядит использование модуля в конфигурации exim’а:

begin transports
remote_smtp:
  driver = smtp
  dkim_domain = ${lookup dkim_domain{$sender_address_domain}{$value}{DKIM_DEFAULT_DOMAIN}}
  dkim_selector = ${lookup dkim_selector{$sender_address_domain}{$value}{DKIM_DEFAULT_SELECTOR}}
  dkim_private_key = ${lookup dkim_privkey{$sender_address_domain}{$value}{DKIM_DEFAULT_KEY}}

Вероятно, вы уже заметили, что для заполнения всех параметров в конфиге делается три lookup'а. Мы решили просто воспользоваться кэшированием: первый запрос получает сразу всю необходимую информацию и сохраняет ее во внутренней переменной модуля, последующие запросы проверяют, закэширована ли необходимая информация, и если да, то в базу уже не обращаются — отдают готовое.

Схема работы следующая: администратор домена через админку добавляет существующий или генерирует новый секретный и публичный DKIM-ключ. Админка сохраняет их в хранилище ключей. При каждой отправке письма от имени бизнес-домена exim запрашивает у базы данных его секретный ключ. Если ключа нет, то для подписи используется дефолтный ключ.

Для связи с БД используется наш стандартный компонент Капрон, о котором мы уже рассказывали ранее в другой статье.

Как мне настроить DKIM?

Если вы уже пользуетесь «Mail.Ru для бизнеса», то настроить собственную DKIM-подпись очень просто:

Как мы реализовали DKIM в «Mail.Ru для бизнеса»

  1. Перейдите на страницу biz.mail.ru с авторизацией ящика администратора домена.
  2. Выберите подключенный домен, для которого необходимо настроить DKIM-подпись.
  3. Перейдите в раздел «Состояние сервера» и проверьте, правильно ли настроена MX-запись. Там же после успешной проверки MX-записи появится значение TXT-записи, которое необходимо установить в DNS-редакторе.
  4. Скопируйте значение TXT-записи и установите в DNS-редакторе вашего домена.
  5. Подождите несколько часов после установки записи, чтобы информация распространилась по всем DNS-серверам.
  6. Если запись настроена верно и прошла все наши проверки, мы отправим вам письмо об успешной настройке и начнем подписывать все ваши письма правильной DKIM-подписью.

Если у вас остались вопросы по поводу настройки и использования DKIM-подписи, оставляйте их в комментариях.

Автор: nikiasi

Источник

Поделиться

* - обязательные к заполнению поля