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 1.1.1.1, 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 a
entries).
v=spf1 ip4:1.1.1.1 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 email@example.net. If I send an email from an IP not allowed by SPF to email@example.com, email@example.net 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-sha256
gives us the algorithms used to sign the messagec=relaxed/relaxed
defines 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 usestrict
instead ofrelaxed
, which would require the content to be 100% identical, or to see the validation fail. For example,c=relaxed/strict
would allow the headers of the email to be reformated, but require the body to be strictly unchanged. Therelaxed
option is convenient to avoid unnecessary failures, as email servers can sometimes reformat the headers during processingd=haveibeenpowned.com
tells us which domain was the signature made forh=[...]
lists the headers that were present when the message was signed (and therefore were included in the hash)s=s1
says that the selector for the domain’s public key iss1
. It will be explained laterbh=[...]
contains the base64 hash of the canonicalized body part of the message. Note that anl
option 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 lengthl
and the DKIM would still be validb=[...]
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 [selector]._domainkey.domain.tld
.
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 header.i=@haveibeenpwned.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:security@example.com; aspf=s; adkim=s; fo=1;
Let’s have a look at the different fields:
v
(mandatory) is the DMARC version (alwaysDMARC1
)p
(mandatory) defines the policy for the domain sent fromexample.com
in the case where the SPF or DKIM check fails. If it is set toreject
nothing will end up in the users’ mailboxes,quarantine
will send emails to spam, andnone
will do nothingpo
does the same asp
but for the sub-domainsruf
allows defining an email address that will receive forensic reports when emails fail the validation.rua
is 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 reportsaspf
allows 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 forexample.com
, a mail sent frommail@test.example.com
will fail the SPF validation if the policy is set to strict, else success if the policy is set to relaxed.adkim
does the same asaspf
but for DKIMfo
allows setting the logging level when emails fail the validation.0
(default) will send reports if both SPF and DKIM fail,1
will send reports if any of DKIM or SPF fails,d
will send an email if the DKIM fails, ands
if this is the SPF. Note that it is possible to combine the rule, for examplefo=0:d;
.
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