A number of email authentication related issues recently came together in a perfect storm to break the delivery of an email which I sent. For mail which I send from grepular.com email addresses, I use three separate features together:
Firstly, I publish strict SPF records, which state that email which comes from a grepular.com email address should only ever come from a small set of known IP addresses:
mike@ung:~$ dig +short txt grepular.com|grep spf "v=spf1 include:spf.grepular.com -all" mike@ung:~$ dig +short txt spf.grepular.com "v=spf1 a:snake.grepular.com a:frank.grepular.com ip4:184.108.40.206 -all"
Secondly, I DKIM sign all of my email:
mike@ung:~$ dig +short txt frank1._domainkey.grepular.com "v=DKIM1; n=\"<script>alert('DKIM XSS')</script>\"; k=rsa; s=email; " "p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCyg6V67GKAwFbbevqJbY4Vt0oRhI9wo0Jy7/Ew4Kjbq5HuV4WTPodI3zKsOsoPNeLeFyh8M/Savz8HVsaa0etYSEquNBMwh1vN6SZDwdN1Nq6XpZk+2LFlbj5Qa2dQM+kCzIXNDWFZ66NLjY7sGqoeGT9IMo5JvrbyjdcyEsaBywIDAQAB"
Thirdly, I publish a DMARC policy which basically states that if my email isn’t authenticated either via SPF or DKIM, then reject it:
mike@ung:~$ dig +short txt _dmarc.grepular.com "v=DMARC1; p=reject; pct=100; rua=mailto:firstname.lastname@example.org; ruf=mailto:email@example.com"
Some people would say that these policies are overly strict, but they usually work OK for me. If the person I’m emailing is using a mail forwarding service and the final server is unaware of the recipients forwarding service and applies SPF checks against mail coming from it, then it will break SPF. And if there is a mailing list which modifies the body or some of the headers, then it may break the DKIM signature. Both need to be broken for the DMARC policy to fail. And because I have configured my DMARC policy to report failures, I am aware when this happens.
Back to the failure: One of my friends set up a small mailing list on his personal server to discuss a regular event which a group of us attend. It doesn’t use any typical mailing list software, it just accepts incoming email and bounces it “untouched” to the other people on the list. This breaks my SPF: The recipients see grepular.com email coming from his server, rather than mine. So for a cheap workaround, I added his servers IP address to my SPF record. This wasn’t a huge problem anyway because he was forwarding the message untouched, so my DKIM signature was not breaking, so my DMARC policy held even if the SPF didn’t.
Without my realising, at some point the list server was reconfigured to start adding Reply-To headers to the emails because one of the recipients was regularly replying directly to senders, rather than back to the list. This started to break my DKIM signature, but it didn’t matter because the SPF policy still held, and therefore my DMARC did too. Then finally, he migrated to a new server with a new IP address and boom, my DMARC policy started to fail, and servers started rejecting my mail to that list.
The immediate fix was to update my horrible hack of placing the list server IP address in my SPF record. But I’ve now added an additional hack, even more horrible than the first, to make my DKIM signatures continue to work when I email the list: When DKIM signing an email, you specify which headers are included in the signature. I’ve reconfigured Exim to exclude signing the Reply-To header when sending email to the list using the dkim_sign_headers feature.
Yes, this is all very brittle, but this is the state of email authentication today.
On a slight tangent, if you go back and take a look at my DKIM record from earlier in this email, you’ll notice I hid an XSS attack in the “notes” section of the record. I like sticking XSS attacks in unexpected places because they randomly alert me to bugs in software that other people write. In the process of looking into this problem, I tested my DKIM with http://dkimvalidator.com - and yes, they failed the encoding test and happily injected my arbitrary script into their own HTML. I reported it and they haven’t got back to me or fixed it. I can’t see a way that it could be leveraged in an attack though so I thought I’d just mention it here for those who are interested in such things.