Add more complexity to your Emails - use DKIM and SPF
October 27, 2012The next thing my paranoid me couldn't stand of is that my emails can be easily spoofed. Yeah, I know I'm not a very famous person, so probability of such thing happening is similar to zero, but hey - tell this to my Paranoid me. :) I also sign every mail I could (they can be easily verified using my public key), but still - DKIM seems to be a fine solution. And besides, I love to play with new things. So after many experiments with dkim-milter, DKIMProxy and opendkim I finally decided to use the last one. Mostly because it's easiest to configure and is still maintained.
Installing and configuring opendkim
You will be suprised how simple it is. :) Firstly you need to install a proper debian packages:
apt-get install opendkim libmail-dkim-perl
The second one is a dkim support for spamassassin. I'll cover that later. Next,
you need to edit your /etc/opendkim.conf
file:
/etc/opendkim.conf
SysLog yes
Umask 002
KeyTable /etc/mail/dkim/KeyTable
SigningTable /etc/mail/dkim/SigningTable
ExternalIgnoreList /etc/mail/dkim/TrustedHosts
InternalHosts /etc/mail/dkim/TrustedHosts
Canonicalization relaxed/simple
Mode sv
X-Header yes
Mode sv
directive tells opendkim to sign but also verify messages, while
X-Header
adds X-Dkim
header (which contains information about the DKIM
daemon you are using). Next we need to tell opendkim which port it will be
using, so in /etc/default/opendkim
uncomment:
/etc/default/opendkim
SOCKET="inet:12345@localhost" # listen on loopback on port 12345
Now we have to populate those extra files we defined. TrustedHosts
is the
easiest one, it's just the list of hosts and domains which are allowed to use
DKIM. So in most cases:
/etc/mail/dkim/TrustedHosts
localhost
127.0.0.1
192.168.1.1
1.2.3.4 # external IP
Next, we need to create a key and DNS TXT record pair for each domain we want
to be signed. I suggest to use strong key (-b
parameter), to avoid
some company's failure
To do this:
mkdir -p /etc/mail/dkim/keys/mydomain.com
cd /etc/mail/dkim/keys/mydomain.com
opendkim-genkey -r -b 2048 -d mydomain.com -s mail
chown opendkim:opendkim mail.private
chmod 600 mail.private
This will create two files: mail.private
- which contains a private RSA key,
and mail.txt
which contains a contents for DNS TXT record. So let's make use
of them! First keys - they need to be fined in KeyTable
and SingingTable
files.
/etc/mail/dkim/KeyTable
mail._domainkey.mydomain.com mydomain.com:mail:/etc/mail/dkim/keys/mydomain.com/mail.private
/etc/mail/dkim/SigningTable
mydomain.com mail._domainkey.mydomain.com
The last thing we need to do is to add a DNS TXT record for
mail._domainkey.mydomain.com
domain containing contents provided by
opendkim-genkey
. For example for irgon.com it looks like this:
mail._domainkey.irgon.com descriptive text "v=DKIM1\; g=*\; k=rsa\; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsfIThdXoizR6sop0gifPwPkT45I/KnTTNKDS4BHWtoU6as62c/3BRQuKqDAIacheZzWbfEPq/M2YvoNrVhx1laltg7aeUhZlcVOtz415lIy8M8oUVTCDxewBKsTEQD5M4Roaadoj7vzpA1JMcOEv36TizFq/KB5GL46pVNyOMJ+Mg" "97F+EQQeiOFsn/T+tNuxWky3l4Qky3S8U34wYmRSr+sVLu4U31QtocwL4uJ7ofVNdVk0baYo7s1HYnM3CGEKK+zdHTR/AoNiquvVX1lLX9s85bade4cNuRaINjzDyM4fAglLgSHZEtRcRlYqdMEpQcplI1OaSxIFS4DpFL3RwIDAQAB"
And that settles DKIM. All we have left is starting it:
/etc/init.d/opendkim start
Connecting opendkim to postfix
This is really simple part.
/etc/postfix/main.cf
# DKIM
milter_default_action = accept
milter_protocol = 6
smtpd_milters = inet:localhost:12345
non_smtpd_milters = inet:localhost:12345
then. reload it and you are set.
Installing SPF
Ok, now THAT is simple. Just install package:
apt-get install postfix-policyd-spf-python
and add service:
/etc/postfix/master.cf
policy-spf unix - n n - - spawn user=nobody argv=/usr/bin/policyd-spf
Add spf timeout to /etc/postfix/main.cf
and adjust
smtpd_recipient_restrictions
to include
check_policy_service unix:private/policy-spf
, so in my file it looks like
this:
/etc/postfix/main.cf
[...]
smtpd_recipient_restrictions = reject_unauth_pipelining,
permit_sasl_authenticated,
permit_mynetworks,
reject_non_fqdn_recipient,
reject_unknown_recipient_domain,
reject_unauth_destination,
reject_unknown_sender_domain,
check_policy_service unix:private/policy-spf
[...]
spf-policyd_time_limit = 3600s
Last but not least is updating a DNS record. This is simple and similar to DKIM -
just ad TXT record to your TLD containing v=spf1 a mx ip4:<your ip>
, for
example my looks like this:
irgon.com descriptive text "v=spf1 a mx ip4:213.134.188.213"
Don't forget to restart your Postfix when you're done!
Testing
To test if everything works fine, just send yourself an email and check it headers. You should see something like:
X-Dkim: OpenDKIM Filter v2.0.1 myexample.com 0224020B8
Dkim-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=myexample.com; s=mail; t=1351357546; bh=Rskt6Q/nZKmxgXkWUYP6cCBSDJhtkVT0PSrUEVGVgp4=; h=From:Content-Type:Content-Transfer-Encoding:Subject:Message-Id: Date:To:Mime-Version; b=phPQdG6HYaders4Xv0TsK2mT+PFYVk/brOFpnmCjCZtvbeGJ+XwrNk4Tnc9xGELtAglLOVplSvMV9nTK6xonta1qLTtnLYPsY4o/WPfyZYDgHmp6X9ZYP4otAHYK3jC00PbKGNqhXeD3bCc7CBV/aVGMQX4Bt0TjAAgndeYCI9VnvR2zH0iTEjlAT2OXrh2JV+wrK5UOXae8gRPT28F2Mg325YOiDwD1T5bgFtfc9mh2s/NRcy7lyDiPcb3CNV+nMXKyq/47o22LlALv5g5+OBBZACQYpYtgalM54InQDPoL/udvKtI/YYaiByFLwqeYFh2LXX6et 9dAiNCRLL+EoA==
Which means that singing is alive and kicking. To test verification, just send yourself an email from DKIM-using provider (like Yahoo or Gmail) and check for following header:
Authentication-Results: myexample.com; dkim=pass (2048-bit key; insecure key) header.i=@gmail.com; dkim-adsp=pass
Which means, that verfication is working. As the last final test, send email to `autorespond+dkim@dk.elandsys.comz. This is automated service, which checks your DKIM headers for you and sends back the results. If you get DKIM Signature validation: passz in the body, then it means, that everything is working properly.
Final polishing
By default spamassassin has DKIM filters enabled. To ensure, look for
loadplugin Mail::SpamAssassin::Plugin::DKIM
in your
/etc/spamassassin/v312.pre
file. When it's enabled you should see values like
DKIM_VALID
or T_DKIM_INVALID
in X-Spam-Status
header. Normally,
spamassassin puts a very little weight to that rules, but you can easily
increase it by adding:
/etc/mail/spamassassin/local.cf
score T_DKIM_INVALID 10
score DKIM_ADSP_CUSTOM_MED 10
You can also add sieve filter based on Authentication-Results
if you want to
treat those suspicious messages differently than normal spam:
.dovecot.sieve
if header :contains "Authentication-Results" "dkim=fail" { fileinto "DANGER"; stop; }
The possibilities are endless :)