Postfix

Dear Lazyweb,

How do I prevent postfix forgeries in "From:" rather than envelope?

Putting "dnalounge.com REJECT Forgery" in "sender_access" prevents inbound unauthenticated SMTP connections from forging my domain in the envelope, but doesn't reject messages like:

Return-Path: spammer@example.com
From: example@dnalounge.com
or
Return-Path: spammer@example.com
From: "example@dnalounge.com" <spammer@example.com>

Looking for a postfix solution, not a spamassassin solution.

Current settings:

smtpd_helo_restrictions =
        permit_mynetworks,
        reject_non_fqdn_helo_hostname,
        reject_invalid_helo_hostname,
        permit

smtpd_sender_restrictions =
        permit_mynetworks,
        reject_non_fqdn_sender,
        reject_unknown_sender_domain,
        permit

smtpd_recipient_restrictions =
        reject_unauth_pipelining,
        reject_non_fqdn_recipient,
        reject_unknown_recipient_domain,
        permit_mynetworks,
        permit_sasl_authenticated,
        reject_unauth_destination,
        check_recipient_access hash:/etc/postfix/access,
        check_sender_access hash:/etc/postfix/sender_access,
        reject_rbl_client zen.spamhaus.org,
        permit

smtpd_relay_restrictions =
        permit_mynetworks,
        permit_sasl_authenticated,
        reject_unauth_destination


Update: I have still not gotten an answer to this question that I understand or believe. Is the person below who said "you can only solve this by adding even more nonstandard complexity to master.cf" correct?

Previously.

Tags: , , , , ,

11 Responses:

  1. AV says:

    On gateway host (routing mail both in an out of internal net) use 2 separate `smtpd`'s and `cleanup`'s for inner and outer mail (separate smtpd for mail from outside could be a good idea anyway); reject anything looking like your domains in `header_checks` for outer `cleanup` (see e.g. https://www.postfix.org/BACKSCATTER_README.html#forged_sender)

    • jwz says:
      2

      I don't understand that in the slightest.

      • Ben Rosengart says:

        It's the MTA/MSA pattern. Look for "submission" in `master.cf`. This service listens on port 587, requires authentication, and doesn't reject mail that claims to be from your domain, because the sender is authenticated. Then the regular "smtp" service on port 25 *can* reject such mail.

  2. cmt says:

    I believe reject_unlisted_sender (to be stuck into smtpd_sender_restrictions) will do half of what you want. The other half looks like it could be implemented as a header_check, but then you're parsing the From-header and doing regular expression matching, and you know what you once said about that and two problems.

    • jwz says:

      As is traditional with Postfix, I cannot figure out what the fuck reject_unlisted_sender does, but it does appear to be about envelopes, not headers. As I said, sender_access already takes care of forged envelopes.

  3. NB says:

    main.cf:

    header_checks = pcre:$config_directory/header_checks

    header_checks:

    /^From: .*spammer@dnalounge.com/ REJECT Forgery

    In typical blog commenter fashion, not a complete solution and it's going to be a royal pain to keep updated.

    • jwz says:

      Isn't that going to reject every legitimate email too? The spam messages are forged from email addresses that exist.

      • AV says:

        As I've said above, you need 2 smtpd processes, for external mail (rejecting your domain in headers, maybe with SASL auth and TLS etc) and for internal (maybe with relaxed restrictions). Also, to implement message body (and headers) checks you'll need 2 `cleanup` daemons; something like this:

        1) replace stock "smtpd" line in master.cf with 2, "extaddr" being internal address or ip and "intaddr" being external hostname or ip; add 2nd "cleanup" service to handle header checks, like

        ```
          # keep 1st "cleanup" in place, add 2nd with addl checks
          cleanup_ext  unix  n       -       n       -       0       cleanup
            #  maybe other options like "-o always_bcc=archive-box@localhost" etc
            -o =header_checks=regexp:/etc/postfix/reject_my_header.re
          # replace stock smtpd with 2 on ext+int addresses
          intaddr:25    inet  n  -     n       -      10       smtpd
          extaddr:25   inet  n  -     n       -      10       smtpd
            -o cleanup_service_name=cleanup_ext
        ```

        reject_my_header.re being

        ```
        /^From:(.*)@mydomain.com$/         REJECT
        ```

        • NB says:

          Or you could assume that authentic email arrives via submission and only outside mail arrives via smtp/s so you can add the "-o header_checks=..." only to the latter in master.cf.

  4. Al Iverson says:

    DMARC potentially solves for this, but will make you itchy because it can make messaging forwarding trickier. I handle it on some of my domains by enabling a p=reject DMARC policy and using OpenDMARC with postfix to reject mail that fails DMARC (which means your legit mail has to be authenticated to pass that test), keeping bad guys from getting through when forging your domain.

  5. Errant Wanderer says:

    From my production mail server main.cf

    smtpd_etrn_restrictions =
            permit_mynetworks,
            reject

    # Mail restrictions in the context of a client SMTP connection request
    smtpd_client_restrictions =
            permit_mynetworks,
            permit_sasl_authenticated,
            check_client_access hash:/etc/postfix/maps/client_access,
            check_client_access cidr:/etc/postfix/maps/client_access.cidr,
            reject_unknown_reverse_client_hostname,
            reject_unknown_client_hostname,
            permit

    # Mail SMTP HELO restrictions
    smtpd_helo_restrictions =
            permit_mynetworks,
            permit_sasl_authenticated,
            check_helo_access hash:/etc/postfix/maps/helo_checks,
            reject_invalid_helo_hostname,
            reject_non_fqdn_helo_hostname,
            reject_unknown_helo_hostname,
            permit

    # Mail FROM restrictions
    smtpd_sender_restrictions =
            check_sender_access regexp:/etc/postfix/amavis/tag_as_originating.re,
            permit_mynetworks,
            permit_sasl_authenticated,
            check_sender_access regexp:/etc/postfix/amavis/tag_as_foreign.re,
            check_sender_access pcre:/etc/postfix/maps/blacklisted_domains,
            check_sender_access hash:/etc/postfix/maps/sender_checks,
            reject_non_fqdn_sender,
            reject_unknown_sender_domain,
            permit

    # Mail RCPT TO restrictions
    smtpd_recipient_restrictions =
            permit_mynetworks,
            permit_sasl_authenticated,
            reject_unauth_pipelining,
            reject_non_fqdn_recipient,
            reject_unknown_recipient_domain,
            reject_unauth_destination,
            check_recipient_access hash:/etc/postfix/maps/recipient_access,
            #
            # Free Spamhaus
            #
            reject_rhsbl_sender               dbl.spamhaus.org=127.0.1.[2..106],
            reject_rhsbl_helo                   dbl.spamhaus.org=127.0.1.[2..106],
            reject_rhsbl_reverse_client    dbl.spamhaus.org=127.0.1.[2..106],
            #
            reject_rbl_client                      zen.spamhaus.org=127.0.0.[2..11],
            reject_rbl_client                      b.barracudacentral.org=127.0.0.2,
            reject_rbl_client                      cbl.abuseat.org=127.0.0.2,
            #
            check_policy_service             inet:127.0.0.1:10023,
            permit

    smtpd_relay_restrictions =·
            permit_mynetworks,·
            permit_sasl_authenticated,
            reject_unauth_destination

    smtpd_data_restrictions =
            reject_unauth_pipelining,
            reject_multi_recipient_bounce,
            permit

    header_checks = pcre:/etc/postfix/checks/header_checks.txt
    body_checks = pcre:/etc/postfix/checks/body_checks.txt

    ....

    $ cat /etc/postfix/maps/helo_checks
    #
    localhost                       REJECT Network Error: You are NOT localhost
    localhost.localdomain   REJECT Network Error: You are NOT localhost.localdomain
    # M$ exchange
    local                              REJECT Network error: .local is not a valid Top Level Domain

    # ipaddr of the external mail server
    NN.NN.NN.NN              REJECT Network Error: You are NOT NN.NN.NN.NN

    #
    dnalounge.com             REJECT Network Error: You are NOT dnalounge.com

    ~~~

    I use header_checks.txt method above as more as a nuclear option/blacklist for e-mails banned from my server.

    HTH