I have been running my own email server for almost 10 years now, and it has been pretty problem-free until now, so I didn’t really think about it that much. I know it’s not an open relay, and that’s about it. If it’s not broken, why fix it right? Ha!
Last week, I discovered that Gmail has been classifying a lot of my emails as junk recently, and it’s annoying, so I decided to look into it, and I’m glad I did!
My first suspicion was that my server is compromised, and someone is using it to spam. However, looking through mail.log, nothing really stood out. There were people brute forcing my server, but they have been doing that for almost 10 years now, and there is no sign of them being successful. While it’s also theoretically possible that the attacker modified the logs, it would have to be a pretty sophisticated and targeted attack, and that’s unlikely since I really don’t have that many enemies (that I know of anyways).
So I decided to change my focus to email spoofing.
Email spoofing is essentially the digital equivalent of sending someone a letter by post, and writing your neighbour’s name and address as the return address. If you think about it, there is really no easy way for the recipient to tell!
There are a few techniques to combat that in the digital world – SPF, DKIM, and DMARC, but I didn’t implement them because they weren’t really a “thing” back when I started my server.
I knew email spoofing is a potential problem, but it sounded so theoretical back then (silly me) that I didn’t really worry about it much.
I decided to implement them now, because better late than never, right?
The 3 aforementioned technologies are designed to work together, and they are actually all very simple in principle.
SPF, Sender Policy Framework, works by the domain owner adding a TXT field to their domain record, that essentially says which IPs are allowed to send emails on behalf of this domain, so if the receiver receives an email claiming to be from this domain, they can do a DNS lookup to get the list, and see if the incoming server is on the list. If not, they know it’s probably fraudulent.
For example, if you do a nslookup on my domain (from a Linux or OS X machine), you’ll see my SPF rule –
matthewlai@~$ nslookup -q=txt matthewlai.ca
matthewlai.ca text = “v=spf1 a mx -all”
Authoritative answers can be found from:
matthewlai.ca nameserver = ns-1442.awsdns-52.org.
matthewlai.ca nameserver = ns-1775.awsdns-29.co.uk.
matthewlai.ca nameserver = ns-274.awsdns-34.com.
matthewlai.ca nameserver = ns-574.awsdns-07.net.
The actual rule is the part in bold. What that means is, both the IPs in the A record (primary IP) and MX record (mail server IP) of the domain name are allowed to send emails on behalf of this domain, and no one else is allowed. In my case the 2 records are actually the same, and I only included both in case I want to separate out the mail server later.
SPF is pretty good, but since it’s purely IP-based, a determined attacker can still get around it by doing a man-in-the-middle attack, and pretend to be the IP in the A record to the receiver, and that’s why people came up with DKIM.
DKIM, or DomainKeys Identified Mail, uses cryptography to provide even more protection, but is otherwise similar to SPF, in that it also uses an extra DNS record for verification.
The server first generates a private key and the corresponding public key. The public key is published in a TXT record, and the server uses the private key to sign all authorized outgoing emails.
This is my public key:
default._domainkey.matthewlai.ca text = “p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCgbviNtlzSeq+66pqhgvgpf4VXSwK5fQE3mvZevaE7MY6WZ7bnVAnUdQUDlAZcxXUY6R/6UqqLYzWcpAsc4uMGhjiU0UnTMAXeEcY/RC+j2hFRSYBw7sz/kfhvSbkJQCUYc5Vp61xd3RLJrl4AvxOUEVLViZsKZIBKCzQp6wmMxQIDAQAB”
default._domainkey.matthewlai.ca text = “v=DKIM1\; k=rsa\; s=email\; “
When the receiver receives an email, it retrieves the public key from the DNS record, and verifies the message signature using that key. If the verification is successful, that means the sender holds the private key, and that the message has not been modified in transit.
Note that the DKIM signature has nothing to do with the more common message signing using personal private keys. On a server using DKIM, all outgoing messages from all users would be signed using the same key, so it’s pretty useless for verifying the individual identity of senders.
SPF and DKIM tell recipients how to identify fraudulent emails, and our last friend DMARC tells them what to do with the result.
DMARC, Domain-based Message Authentication, Reporting and Conformance, adds yet another DNS record.
My DMARC rule looks like this:
_dmarc.matthewlai.ca text = “v=DMARC1; p=reject; rua=mailto:[my email]”
What that means is I want recipients of emails that fail both SPF and DKIM to be rejected – usually in the email world rejected means dropped, not bounced, because the claimed sender (myself in this case) is probably not the real sender.
The even more interesting part is rua. It tells other servers also using DMARC to send me an aggregated report per day, about all emails they received that claim to be from me.
A few hours later, I got a report from Gmail in XML format, and I used dmarcian.com to convert that to nice graphs (I would link to it, but I don’t think I can).
It says over the past 24 hours, there were 9 emails from my server (SPF pass), which sounds about right, and 20 emails from other servers!
Other domains were imperial.ac.uk, mit.edu, bhosted.nl, outlook.com, hotmail.com, and yahoo.com.
Interesting huh? I’m sure the ones from Imperial are not from me, because I don’t use their SMTP server, and I didn’t even go on campus in the past 24 hours, or connect to their VPN.
But the fact that Imperial is on the list is interesting. It could be a coincidence, but what’s the chance of that happening?
I believe what’s happening is either someone is trying to impersonate me at Imperial, or the more likely explanation – some of the people I sent emails to have a compromised system that’s collecting email addresses, and the attacker is trying to send out spoofed emails using their locally configured SMTP server (which would most likely be Imperial’s).
I will never know which one is true, since Google reports doesn’t give me the content of those emails, but either way, I hope my SPF+DKIM+DMARC (that’s a lot of acronyms!) will stop that now!
And Gmail is accepting my emails again after I added DMARC and DKIM signatures!
Moral of the story: If you run your own email server, make sure you are using SPF+DKIM+DMARC to protect yourself and your recipients!
EDIT: Apparently DMARC reject will cause problems with mailing lists. I have changed my policy to “none” for now (meaning the receiving server will use their own judgement for what to do with emails that fail SPF and DKIM), until a better solution comes along. If you don’t care about mailing lists, it should be fine to use “reject”.