Назад | Перейти на главную страницу

Переписать адрес электронной почты (RFC822) от адреса в соответствие с почтовым индексом почтового адреса из конверта (RFC821)

Я предпринимаю шаги по усилению защиты моего SMTP-сервера исходящей почты. Я хочу запретить пользователям подделывать адрес отправителя.

При отправке электронной почты с постфиксным SMTP отправитель идентифицируется тремя способами:

  1. В самом письме есть From: заголовок - как определено в RFC 822
  2. При отправке по SMTP есть MAIL FROM адрес - как определено в RFC 821
  3. При входе в postfix (SMTP) клиент указывает имя пользователя, которое также может интерпретироваться как отправитель.

Глядя в руководство, я считаю, что reject_sender_login_mismatch и reject_unlisted_sender вместе гарантирует, что MAIL FROM адрес электронной почты, связанный с логином postifx. Это 2 и 3 совпадения.

Я застрял в том, как обеспечить совпадение всех трех. Я счастлив, если результат просто переписывает сообщение, а не отклоняет, но все будет хорошо. Однако я не вижу способа сделать это. Я это вижу уборка добавит недостающий From: заголовок, но я не вижу возможности проверить и переписать его.


Спасибо тем, кто указал еще один похожий вопрос. К сожалению, это не помогло, так как на этот вопрос есть два ответа: один очень расплывчатый, другой кажется неправильным.

Я потратил некоторое время на изучение этого и не могу найти чистый постфиксный способ. Единственное предложение использовать header_checks похоже, не работает, потому что вы не можете (AFAIK) сопоставить один заголовок с другим.

Можно написать свою собственную программу / сценарий для выполнения проверки за вас и использовать ее как content_filter.


Шаг 1

Вот упрощенная версия того, что я использую, написанное на python. Это читает письмо от stdin, принимающего MAIL from и RECPT to адреса как аргументы. Он проверяет From: заголовок против MAIL from и заменяет его, если они не совпадают. Я сохраняю это как /usr/share/mail_filter/filter.py:

#! /usr/bin/python3

import sys
import subprocess
import email.parser
import email.policy

parser = email.parser.BytesParser(policy=email.policy.default)
message = parser.parse(sys.stdin.buffer)

envelope_from = sys.argv[1]
envelope_to = sys.argv[2]
# This if statement checks envelope from against message from
if message['From'].addresses[0].addr_spec != envelope_from:
    print(f"Replacing sender {message['from']} with {envelope_from}", file=sys.stderr)
    message.replace_header('From', envelope_from)

# sendmail -G -i -f sender@sender_domain.tld recipient@recipient_domain.tld
sendmail = subprocess.Popen(["/usr/sbin/sendmail", "-Gif", envelope_from, envelope_to], stdin=subprocess.PIPE)
with sendmail.stdin:
    sendmail.stdin.write(message.as_bytes())

# If sendmail returns an error, cascade it back to postfix
sys.exit(sendmail.wait())

Шаг 2

Обновлено /etc/postfix/master.cf:

# added the -o content_filter...
smtp inet n       -       y       -       -       smtpd
  -o content_filter=filter:dummy

# Added this entire service
filter    unix  -       n       n       -       10      pipe
  flags=Rq user=filter null_sender=
  argv=/usr/share/mail_filter/filter.py ${sender} ${recipient}

Обратите внимание, что это ссылается на расположение сценария из шага 1 и пользователя, определенного в шаге 3.

Шаг 3

Я добавил пользователя ОС filter в группе с доступом к использованию sendmail.

useradd --system --gid postdrop filter

Предостережения

В соответствии с инструкции простые фильтры (переход вперед с использованием sendmail) может применяться только к клиентам SMTP и не может фильтровать сообщения, отправленные через sendmail. Если это проблема для вас, вам нужно будет написать расширенный фильтр содержимого.