postfix sender restrictions

I mentioned in my previous post that I had recently received one of those scam emails designed to make the recipient think that their account has been compromised in some way and that, furthermore, that compromise has led to malware being installed which has spied on the user’s supposed porn habits. The email then attempts a classic extortion along the lines, “send us money or we let all your friends and contacts see what you have been up to.”

In the scam as described by El Reg, the sender tries to lend credence to the email by including the recipient’s password. As the Reg points out, this password is likely to have been harvested from a web site used in the past by the poor unsuspecting recipient. In my case, the sender didn’t include any password, but they did send the email to me from the email address targetted (so they sent email to “mick@domain” with sender “mick@domain”). Needless to say, I thought that this should not have been possible (except in the unlikely scenario that the extortionist actually had compromised my mail server). After all, my mail server refuses to relay from addresses other than my own networks, and all mail sent from my server must come from an authenticated user (using SASL authentication). My postfix sender restrictions looked like this:

# sender relaying restrictions – authenticated users can send to anywhere

smtpd_sender_restrictions = permit_sasl_authenticated, permit_mynetworks, reject_non_fqdn_sender, permit

That says that locally authenticated users can send mail anywhere, but we should reject the sending request when the MAIL FROM address specifies a domain that is not in fully-qualified domain form as is required by the RFC. This stops outsiders trying to send mail to us from non-existent or badly forged from addresses. The final permit allows checking to proceed to the next steps (the relay and recipient restrictions).

So what was going on?

Well, there was nothing in my restrictions to say that an outsider could not send to a local user (i.e. an email recipient on one of my domains). After all, that is part of the function of my mail system – it must accept (valid) email from the outside world aimed at my local users. But therein lay the problem. My mail connection checks (along with the “smtpd_helo”, “smtpd_relay” and “smtpd_recipient” restrictions enforced outbound checks and limited mail sending to outside domains from locally authenticated users, but inbound checks assumed (incorrectly as it turns out) that the sender domain was external to me (i.e. FROM someone@external.domain TO someone@internal.domain). Crucially I had ommitted to enforce any rule stopping someone sending FROM someone@internal.domain TO someone@internal.domain). On reflection that was dumb – and the “extortionist” had taken advantage of that mistake to try to fool me.

Fixing this is actually quite easy. Postfix allows the smtpd_sender_restrictions to include a variety of checks, one of which is “check_sender_access”. This enforces checks against a database of MAIL FROM address, domains, parent domains, or localpart@ specifying actions to take in each case. The database table contains three fields – domain-to-check, action-to-take, optional-message.

So I created a database of local domains called /postfix/localdomains thus:

first.local.domain REJECT Oh no you don’t. You’re not local!
second.local.domain REJECT Oh no you don’t. You’re not local!
third.local.domain REJECT Oh no you don’t. You’re not local!

(I was tempted to add a rude message, but thought better of it…..)

Postfix supports a variety of different table types. You can find out which your system supports with the command “postconf -m”. I chose “hash” for my table. The local database file is created from the text table with the command “postmap /etc/postfix/localdomains”. Having done that I added the check to my sender_restrictions thus:

smtpd_sender_restrictions = permit_sasl_authenticated, permit_mynetworks, reject_non_fqdn_sender, check_sender_access hash:/etc/postfix/localdomains, permit

and reloaded postfix. Job done.

Permanent link to this article: