SPF, DKIM, and DMARC: How to Protect Yourself from People Impersonating You via Email
Table of Contents
Nowadays, emails are a wildly used form of communication. Therefore, they are also wildly used as an attack vector. 75% of organizations worldwide are said to have experienced phishing in 2020, and up to 95% of social engineering attacks may be delivered through emails. Of course, there is no magic to prevent all of these attacks from happening, but there are a couple of mechanisms that can help to prevent malicious people from impersonating you via email. These mechanisms only require a few DNS entries to be set (unless you are running your own email server, which we will not cover here). Even better, setting these DNS entries will also improve the delivery of your emails, as they will be less likely to be flagged as spam.
Sender Policy Framework (SPF) #
Simply put, SPF allows listing servers that are permitted to send emails using a domain name. When an email is sent, the receiving server will query the SPF entry of the sender domain (recovered from the
envelope-from) and compare it with the server it is receiving the email from. If this is not matching, the email could be flagged or rejected (ultimately, the receiving server decides what it wants to do).
The configuration is pretty simple, as it just requires you to add a
TXT entry to your DNS configuration. For example, the following (content of a DNS TXT entry) allows all the emails coming from 188.8.131.52, 192.168.0.1/8, and the
A record of
example.com, and says that other servers are not authorized to send emails for this domain name. Note that a rule cannot have more than 10 lookups (e.g., resolving
v=spf1 ip4:184.108.40.206 ip4:192.168.0.1/8 a:example.com -all
In addition to allowing IP v4 addresses and range, domain names, many other options such as IP v6 and MX are available.
Instead of using
-all to have the SPF check fail if emails are not sent from an allowed server,
~all could be used to produce a soft-fail,
?all to state that nothing can be said about the addresses not explicitly marked.
+all could also be used to signal that any server is allowed to send emails on the behalf of our domain name
All of this is nice, but SPF is not perfect. Let’s say that you configured your mailbox email@example.com to forward automatically emails to firstname.lastname@example.org. If I send an email from an IP not allowed by SPF to email@example.com, firstname.lastname@example.org will not see that the original SPF is invalid.
Domain Keys Identified Mail (DKIM) #
We mentioned in the previous part that SPF by itself is not enough to guarantee emails’ authentication for reasons such as being ignored when emails are forwarded. DKIM is another option to authenticate the emails, and it has the advantage of not being lost when emails are forwarded.
The way DKIM works is pretty simple. The domain of the sender needs to have a DNS entry (you will need to refer to your email hosting provider to see how they expect things to be configured) with a public key. The corresponding private key will be used to sign sent emails. When an email is received, the receiving server will pull the public key from the DNS records of the domain name used by the sender, and check that the signature is correct.
Let’s look at an example. The following is part of the header of a received email that was sent from a server using DKIM.
Dkim-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=haveibeenpwned.com; h=content-type:from:mime-version:to:subject:list-unsubscribe; s=s1; bh=XnUR5B4bb9/iGnKkBNkjeCE5H9eTJoZZhuc28eSwj/Y=; b=CwFiOJD nrpW8docGIVBd/A+bPcOjmmVg0letY5gf43QQTSD3V1bJ4wkt3l1LSBT1uDqhkzK QxBQttzZIxnmcYY5E/sP/tj1UseO0KEBq/s6Mt1X5AHtvDScaIJgoTfeay3sIU+O 6Edb/G0uCDhSW6JY8gAnXgVKFcooGBp43+yk=
We can see multiple fields:
a=rsa-sha256gives us the algorithms used to sign the message
c=relaxed/relaxeddefines the canonicalization posture of the sending domain. Here, the configuration will make some reformating before hashing the message, such as putting the header names in lowercase, removing line trailing whitespace and such. Another option would be to use
relaxed, which would require the content to be 100% identical, or to see the validation fail. For example,
c=relaxed/strictwould allow the headers of the email to be reformated, but require the body to be strictly unchanged. The
relaxedoption is convenient to avoid unnecessary failures, as email servers can sometimes reformat the headers during processing
d=haveibeenpowned.comtells us which domain was the signature made for
h=[...]lists the headers that were present when the message was signed (and therefore were included in the hash)
s=s1says that the selector for the domain’s public key is
s1. It will be explained later
bh=[...]contains the base64 hash of the canonicalized body part of the message. Note that an
loption could be provided in the parameters, to specify the max length of the body that will be used to calculate the hash. That means that content could be included after length
land the DKIM would still be valid
b=[...]contains the base64 signature
When the receiving server gets the message, it will try to see if the signature provided in
b is valid. For that, it will make a DNS query to get the key for the domain that sent the email, and receive the following:
user@Host ~ % dig TXT s1._domainkey.haveibeenpwned.com [...] ;; ANSWER SECTION: s1._domainkey.haveibeenpwned.com. 300 IN CNAME s1.domainkey.u3489673.wl174.sendgrid.net. s1.domainkey.u3489673.wl174.sendgrid.net. 474 IN TXT "k=rsa; t=s; p=[key]"
You will notice the
s1 in the dig query. This is the selector value that was in the
s field of the DKIM header of the email. DKIM entries will always be stored for
Once it got the key provided in the DNS reply, the receiving server will verify that the signature is valid and matching the content. If not, the verification fails. Otherwise, something looking as follows will be added to the email headers.
Authentication-Results: mailin007.protonmail.ch; dkim=pass (1024-bit key) header.d=haveibeenpwned.com email@example.com header.b="EwFk1JDn"
Domain-based Message Authentication, Reporting and Conformance (DMARC) #
If you followed everything until here, your email server address is now part of a SPF entry, and your messages are signed thanks to DKIM. This is good, but what happens if an attacker decides to forge a message, and send it from his server (without including any DKIM)? In this scenario, the email will likely be allowed by the recipient server, and end up in the recipient’s mailbox.
This is where DMARC comes in handy. This mechanism has the following benefits:
- It allows giving guidelines to the receiving email servers on how to process emails failing SPF or DKIM checks (even if there is no obligation whatsoever for the servers to enforce it)
- It allows extra options to manage SPF with subdomains (note that servers matching ~all will be marked as a fail)
- It allows getting some feedback on the email sent using our domain name, which comes in handy for debugging or detecting malicious activity
- DMARC checks that RFC5321’s Mailfrom header and the RDC5322’s Mailfrom header are matching to address a weakness in DMARC and SPF
As for the two other items, DMARC is set through a single TXT DNS field that will be located at
_dmarc.domain.com. The following snippet shows an example of configuration.
v=DMARC1; p=reject; sp=reject; ruf=mailto:firstname.lastname@example.org; aspf=s; adkim=s; fo=1;
Let’s have a look at the different fields:
v(mandatory) is the DMARC version (always
p(mandatory) defines the policy for the domain sent from
example.comin the case where the SPF or DKIM check fails. If it is set to
rejectnothing will end up in the users’ mailboxes,
quarantinewill send emails to spam, and
nonewill do nothing
podoes the same as
pbut for the sub-domains
rufallows defining an email address that will receive forensic reports when emails fail the validation.
ruais a similar option that will send daily (less detailed) aggregated reports of the activity involving our domain (e.g., if you send emails to Gmail during the day, Gmail will send you a report aggregating the various operations at the end of the day). Note that some servers will not send reports
aspfallows setting an extra policy for the SPF. It can either be strict (
s) or relaxed (
r). In the case where you have an SPF record for
example.com, a mail sent from
email@example.com fail the SPF validation if the policy is set to strict, else success if the policy is set to relaxed.
adkimdoes the same as
aspfbut for DKIM
foallows setting the logging level when emails fail the validation.
0(default) will send reports if both SPF and DKIM fail,
1will send reports if any of DKIM or SPF fails,
dwill send an email if the DKIM fails, and
sif this is the SPF. Note that it is possible to combine the rule, for example
Useful Tools #
Here is a list of tools that I think are helpful when it comes to configuring DNS email entries.
- mxtoolbox.com - Various online tools to allow checking your email configuration
- mail-tester.com - will give a mark to the emails sent from your email server, and tell you if things are not working or should be improved
- whatsmydns.net - allows you to check if DNS entries are properly propagated