Securing your email domain with DMARC, DKIM and SPF

in

Having a number of domains that were registered long time ago and even once used for sending any email typically results in tons of spam being not only sent to these addresses — which you can just filter and ignore — but also from them as they are used to build fake headers by the spam software. Here's one method to deal with that.

Fake From headers in spam email are a known and widespread problem. I have experienced this with echelon.pl that I registered back in 2001 and for a while used on a mail server for friends: it's quite amazing to see rejected spam still arriving in 2015 for lcamtuf@echelon.pl because of two emails Michał has posted back in 2001 to a mailing list from that address!

Fortunately, there are now methods that are quite effective in preventing this type of (rather minor) reputation damage:

  • Sender Policy Framework (SPF) to declare what IP addresses are authorised to send email from the echelon.pl. So this is what I declare in the DNS for this domain: this essentially means that no servers are today authorised to send email from this domain:
    $ dig txt echelon.pl
    echelon.pl.     299 IN  TXT "v=spf1 -all"

    As result, if GMail server receives an email allegedly from someone@echelon.pl sent by a server in China, by consulting SPF it can easily decide it's fake — because no mail should be coming from that domain at all.
  • DomainKeys Identified Mail (DKIM) to digitally sign emails confirming the authenticity of the From header (as minimum). The echelon.pl domain doesn't send any email, so it doesn't sign it, so if not SPF then lack of the DKIM header should be per se suggestion that the email is fake. But I do send email from ipsec.pl domain, it is signed by DKIM and here's how the public key used to verify the messages looks like in DNS:
    $ dig txt mail._domainkey.ipsec.pl
    mail._domainkey.ipsec.pl. 299   IN  TXT "v=DKIM1\; k=rsa\; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDRjElXjPoQWDZnO89V9WzJmIORhUtjCdiDdqSL3/y2fHI+q1f1sebLOLjpCN2zzQxPM9+pkCBZGp4PZGNa32g/h1hQmNo2XT4px9Hwghh8HaZ5nQOeMvn+i4jfSn4nh9+Dpg7l2bwL9vRwBuPBbOkDElT3LBORNCh4m45QpKqV4QIDAQAB"
  • Domain-based Message Authentication, Reporting, and Conformance (DMARC) as an umbrella protocol that actually tells the mail servers what to do with all the possible violations SPF and DKIM. In short, it can instruct the recipient mail server at Google that "we're now testing SPF and DKIM, so please not reject our email" or "be pretty strict and reject all email that doesn't pass the tests". The latter is pretty much what the following policy says for echelon.pl: be strict in checking DKIM and SPF for emails received allegedly from echelon.pl, reject anything non-compliant and report these violations to the specified email address:
    $ dig txt _dmarc.echelon.pl
    _dmarc.echelon.pl.  299 IN  TXT "v=DMARC1\; p=reject\; pct=100\; rua=mailto:reports@echelon.pl\; adkim=s\; aspf=s"

If you want to protect domains that don't send or receive emails, then the only place you need to update is your DNS — just go and have a look at the pages linked above for what to actually place there. If you want to process SPF, DKIM and DMARC on your email server and sign outgoing email, there's again tons of manuals on how to do this on specific brands (I'm using Postfix and OpenDKIM on Ubuntu), so I won't repeat it here.

And here's an example report I have received from Google email server (and I get similar from Yahoo and others). This is what is says:

  • We received an email allegedly from echelon.pl sent by a Chinese IP 218.109.253.163 (record section)
  • You anounce a policy (policy_published) that requires us to be strict with SPF and DKIM validation for this domain and reject non-compliant email.
  • Because the email failed all these validations (policy_evaluated) we have rejected this email as you wished.

<?xml version="1.0" encoding="UTF-8" ?>
<feedback>
  <report_metadata>
    <org_name>google.com</org_name>
    <email>noreply-dmarc-support@google.com</email>
    <extra_contact_info>http://support.google.com/a/bin/answer.py?answer=2466580</extra_contact_info>
    <report_id>5315746295773458280</report_id>
    <date_range>
      <begin>1426464000</begin>
      <end>1426550399</end>
    </date_range>
  </report_metadata>
  <policy_published>
    <domain>echelon.pl</domain>
    <adkim>s</adkim>
    <aspf>s</aspf>
    <p>reject</p>
    <sp>reject</sp>
    <pct>100</pct>
  </policy_published>
  <record>
    <row>
      <source_ip>218.109.253.163</source_ip>
      <count>1</count>
      <policy_evaluated>
        <disposition>reject</disposition>
        <dkim>fail</dkim>
        <spf>fail</spf>
      </policy_evaluated>
    </row>
    <identifiers>
      <header_from>echelon.pl</header_from>
    </identifiers>
    <auth_results>
      <spf>
        <domain>echelon.pl</domain>
        <result>fail</result>
      </spf>
    </auth_results>
  </record>
</feedback>