Почему пересылка почты ломает SPF и что делают SRS и ARC
Пересланные письма не проходят SPF, потому что IP пересыльщика нет в записи отправителя. Как SRS, DKIM и ARC меняют результат и что с этим делает DMARC.
Опубликовано: · 7 мин чтения
Пересылка почты ломает SPF, потому что SPF сравнивает IP-адрес подключившегося сервера с записью домена отправителя конверта, а простой пересыльщик меняет первое, не меняя второго. Конечный получатель видит, что сервер пересыльщика доставляет письмо «от» example.com, не находит этот сервер в SPF-записи example.com и возвращает fail. Ни на одной из сторон ничего не настроено неправильно: так SPF устроен. Пройдёт ли письмо DMARC, почти целиком зависит от DKIM.
В этой статье мы проследим путь одного письма через пересыльщика и посмотрим, что именно меняют SRS, DKIM и ARC.
Что на самом деле проверяет SPF
У доставки по SMTP два адреса отправителя:
- отправитель конверта, который передаётся в команде
MAIL FROMи позже записывается какReturn-Path. Туда уходят возвраты (bounce). - заголовок From, который показывает почтовый клиент получателя.
SPF (RFC 7208) знает только о первом. Получатель берёт домен отправителя конверта (или имя из HELO как запасной вариант, например когда отправитель конверта пуст, как в возвратах), получает его SPF-запись и спрашивает: есть ли в ней IP-адрес, который подключается ко мне прямо сейчас?
Прямая доставка:
alice@example.com -> mail server of example.com (192.0.2.10) -> receiver
MAIL FROM:<alice@example.com> connecting IP 192.0.2.10 spf=pass
Что делает простой пересыльщик
Простой пересыльщик — это алиас, файл .forward, правило «пересылать всю почту на» или пересылка почты, которая прилагается к домену у многих регистраторов. Он принимает письмо и отправляет его заново на другой адрес, сохраняя исходного отправителя конверта, чтобы возвраты уходили автору.
alice@example.com -> forwarder (203.0.113.7) -> bob's real mailbox
MAIL FROM:<alice@example.com> connecting IP 203.0.113.7 spf=fail
203.0.113.7 принадлежит пересыльщику. example.com о нём никогда не слышал и не должен его перечислять: отправитель не может знать все адреса, на которые его получатели пересылают почту.
SRS: починка SPF для пересыльщика
Sender Rewriting Scheme меняет отправителя конверта на адрес в собственном домене пересыльщика перед повторной отправкой:
MAIL FROM:<SRS0=HHH=TT=example.com=alice@forwarder.example>
HHH — короткий хеш, TT — метка времени, а исходные домен и локальная часть сохраняются, чтобы возврат, присланный на этот адрес, можно было распаковать и передать дальше на alice@example.com. Хеш не даёт посторонним использовать пересыльщика как ретранслятор возвратов.
Теперь получатель проверяет SPF-запись forwarder.example, в которой 203.0.113.7 есть. SPF проходит.
Две вещи, которые нужно знать об SRS:
- Это не стандарт IETF. Это спецификация сообщества, вышедшая из проекта SPF, и реализации отличаются в деталях.
- Она чинит SPF, а не DMARC. После переписывания домен, аутентифицированный через SPF, — это
forwarder.example, тогда как в заголовке From по-прежнему стоитexample.com. DMARC требует, чтобы аутентифицированный домен был выровнен с доменом From, поэтому SPF-ветка DMARC всё равно не проходит. Просто проваливается она тихо, а не громко.
DKIM: часть, которая выживает
DKIM-подпись — часть письма, а не соединения. Она покрывает тело и выбранный набор заголовков и проверяется открытым ключом из DNS подписавшего. Пересыльщик, передающий письмо без изменений, оставляет подпись действительной, с какого бы IP он ни подключался. Если подписывающий домен (d=) выровнен с доменом From, DMARC проходит по одной только DKIM-ветке.
DKIM ломается, когда меняется подписанная часть:
- список рассылки добавляет
[имя-списка]в тему или подвал в тело письма; - шлюз переписывает тело, например добавляя дисклеймер или подменяя ссылки;
- система перекодирует письмо так, как канонизация подписи не допускает.
Простая пересылка ничего из этого не делает. Списки рассылки делают первое постоянно.
Таблица сценариев
Допустим, example.com публикует SPF, подписывает письма с d=example.com и держит p=reject.
| Сценарий | Результат SPF | Результат DKIM | Результат DMARC |
|---|---|---|---|
| Прямая доставка | pass, выровнен | pass, выровнен | pass |
| Простая пересылка, письмо не тронуто | fail | pass, выровнен | pass (через DKIM) |
| Простая пересылка, у отправителя нет DKIM | fail | none | fail |
| Пересылка с SRS, письмо не тронуто | pass для пересыльщика, не выровнен | pass, выровнен | pass (через DKIM) |
| Пересылка с SRS, у отправителя нет DKIM | pass для пересыльщика, не выровнен | none | fail |
| Список рассылки, меняющий тему или тело | pass для списка, не выровнен | fail (сломан) | fail, если только список не переписывает From |
| То же, с цепочкой ARC, которой получатель доверяет | как выше | как выше | fail, но получатель может переопределить локально |
На практике важны вторая и пятая строки: SRS не спасёт отправителя без выровненного DKIM, а отправителю с выровненным DKIM SRS для прохождения DMARC не нужен.
ARC: передать дальше то, что видел посредник
Authenticated Received Chain (RFC 8617, статус Experimental) отвечает за строки со списками рассылки. Посредник, обрабатывающий письмо, записывает результаты аутентификации, которые он наблюдал при получении, и подписывает эту запись. Каждый узел добавляет набор из трёх заголовков с порядковым номером:
ARC-Authentication-Results: i=1; lists.example.org;
spf=pass smtp.mailfrom=example.com; dkim=pass header.d=example.com;
dmarc=pass header.from=example.com
ARC-Message-Signature: i=1; a=rsa-sha256; d=lists.example.org; s=arc1; …
ARC-Seal: i=1; a=rsa-sha256; cv=none; d=lists.example.org; s=arc1; …
Второй посредник добавляет i=2, и так далее. Конечный получатель может проверить цепочку и увидеть, что письмо проходило DMARC, когда пришло на lists.example.org, до того как список его изменил.
Ключевое слово — может. ARC сообщает получателю, что заявляет увидевший письмо подписант. Верить ли этому подписанту — вопрос локальной политики: получатели MAY учитывать цепочку от посредника, которому доверяют, и вольны её игнорировать. ARC не гарантирует доставку.
Из-за этой неопределённости списки рассылки для отправителей, чьи домены применяют DMARC, обычно поступают грубее: переписывают заголовок From на адрес в собственном домене списка, чтобы письмо было выровнено с SPF и DKIM самого списка.
Как читать заголовок Authentication-Results
Отправьте письмо через пересыльщика на ящик, которым вы управляете, откройте исходный текст и найдите заголовок Authentication-Results, добавленный конечным получателем (самый верхний):
Authentication-Results: mx.receiver.example;
spf=pass smtp.mailfrom=forwarder.example;
dkim=pass header.d=example.com header.s=s2026;
dmarc=pass header.from=example.com;
arc=pass
Return-Path: <SRS0=a1b2=XY=example.com=alice@forwarder.example>
| Поле | О чём говорит |
|---|---|
smtp.mailfrom= |
Домен, по которому проверялся SPF. Если это домен пересыльщика, используется SRS. |
spf= |
Результат для этого домена и подключившегося IP. fail с исходным доменом означает простого пересыльщика. |
header.d= |
Домен, чья DKIM-подпись прошла проверку. Сравните его с header.from. |
dmarc= |
Вердикт после выравнивания. Именно он решает. |
arc= |
Была ли цепочка ARC и прошла ли она проверку. |
Если заголовки удобнее вставить, чем читать, анализ заголовков письма разберёт их по частям.
Советы отправителям
- Подписывайте всё DKIM с выравниванием по домену From. Каждый сервис, отправляющий от вашего имени: почтовый провайдер, сервис рассылок, выставление счетов, служба поддержки. Именно это позволяет вашей почте пережить пересылку. Один SPF не переживёт её никогда.
- Не добавляйте IP-адреса пересыльщиков в свою SPF-запись. Вы не можете знать их все, они меняются, а каждый добавленный include идёт в счёт лимита в 10 запросов.
- Переходите на
p=rejectтолько тогда, когда отчёты DMARC показывают выравнивание DKIM у всех легитимных источников. Домену наp=reject, который опирается на один SPF, будут отказывать в доставке пересланной почты. - Ожидайте небольшой остаток сбоев от списков рассылки. Порядок внедрения из статьи MX, SPF, DKIM и DMARC: как они работают вместе это учитывает.
Советы тем, кто пересылает почту
- Используйте пересыльщика, который реализует SRS, а в идеале и подписание ARC. Без SRS каждое письмо с домена с
-allприходит сspf=fail. - Подумайте о сборе вместо пересылки. Если целевой ящик может забирать почту из старой учётной записи по POP или IMAP, повторной отправки не происходит и аутентификация не нарушается.
- Не пересылайте спам. Конечный получатель видит, что его доставляет IP вашего пересыльщика, и ставит это пересыльщику в вину. Фильтруйте до пересылки.
- Подумайте о размещении ящика вместо пересылки. Домен, который только пересылает почту на бесплатный ящик, — хрупкая конфигурация, стоящая за большинством обращений «у меня пропадает почта»: см. чек-лист проверки DNS для писем, попадающих в спам.
Частые ошибки
- Принимать
spf=failна пересланном письме за доказательство подделки. Прежде чем решать, посмотрите наdkim=иdmarc=. - Верить, что SRS чинит DMARC. Он чинит SPF для домена пересыльщика; выравнивание по-прежнему потеряно.
- Добавлять записи
include:для пересыльщиков получателей в собственную SPF-запись. - Переходить на
p=rejectс аутентификацией только по SPF, потому что «во всех наших тестах SPF проходит». В тестах редко участвует пересыльщик. - Считать, что ARC обязывает получателя принять письмо. Это свидетельство, предложенное получателю, который может доверять подписанту, а может и нет.
- Добавлять дисклеймер на исходящем шлюзе после подписания DKIM. Так вы ломаете собственную подпись ещё до того, как письмо покинуло вас.
Проверьте в OrbitProbe
Проверка SPF в OrbitProbe показывает SPF-запись, которую публикует домен, и отмечает обычные структурные проблемы: несколько записей, +all, отсутствующий механизм all, слишком много DNS-запросов. При проблеме с пересылкой проверьте два имени: домен исходного отправителя (заканчивается ли запись на -all, из-за чего простая пересылка проваливается жёстко?) и домен пересыльщика (есть ли у него вообще действительная запись, чтобы почта, переписанная через SRS, могла пройти?). Проверка DNS читает опубликованную политику. Что случилось с одним конкретным письмом, записано только в заголовке Authentication-Results этого письма, так что читайте и то и другое.