Securing registration email
I've been running my own email server basically forever. Recently, I've been thinking about possible attack vectors against my personal email. There's of course a lot of private information in that email address, and if someone manages to compromise my email account, they will see a lot of personal information. That's somewhat worrisome, but there are possibly more serious problems to worry about.
TL;DR: if you can, create a second email address to register on websites and use stronger protections on that account from your regular mail.
Hacking accounts through email
Strangely what keeps me up at night is more what kind of damage an attacker could do to other accounts I hold with that email address. Because basically every online service is backed by an email address, if someone controls my email address, they can do a password reset on every account I have online. In fact, some authentication systems just gave up on passwords algother and use the email system itself for authentication, essentially using the "password reset" feature as the authentication mechanism.
Some services have protections against this: for example, GitHub require a 2FA token when doing certain changes which the attacker hopefully wouldn't have (although phishing attacks have been getting better at bypassing those protections). Other services will warn you about the password change which might be useful, except the warning is usually sent... to the hacked email address, which doesn't help at all.
The solution: a separate mailbox
I had been using an extension (anarcat+register@example.com
) to
store registration mail in a separate folder for a while already. This
allows me to bypass greylisting on the email address, for
one. Greylisting is really annoying when you register on a service or
do a password reset... The extension also allows me to sort those
annoying emails in a separate folder automatically with a simple
Sieve rule.
More recently, I have been forced to use a completely different email
alias (register@example.com
) on some services that dislike having
plus signs (+
) in email address, even though they are perfectly
valid. That got me thinking about the security problem again: if I
have a different alias why not make it a completely separate
account and harden that against intrusion. With a separate
account, I could enforce things like SSH-only access or 2FA that would
be inconvenient for my main email address when I travel, because I
sometimes log into webmail for example. Because I don't frequently
need access to registration mail, it seemed like a good tradeoff.
So I created a second account, with a locked password and SSH-only authentication. That way the only way someone can compromise my "registration email" is by hacking my physical machine or the server directly, not by just bruteforcing a password.
Now of course I need to figure out which sites I'm registered on with
a "non-registration" email (anarcat@example.com
): before I thought
of using the register@
alias, I sometimes used my normal address
instead. So I'll have to track those down and reset those. But it
seems I already blocked a large attack surface with a very simple
change and that feels quite satisfying.
Implementation details
Using syncmaildir (SMD) to sync my email, the change was fairly simple. First I need to create a second SMD profile:
if [ $(hostname) = "marcos" ]; then
exit 1
fi
SERVERNAME=smd-server-register
CLIENTNAME=$(hostname)-register
MAILBOX_LOCAL=Maildir/.register/
MAILBOX_REMOTE=Maildir
TRANSLATOR_LR="smd-translate -m move -d LR register"
TRANSLATOR_RL="smd-translate -m move -d RL register"
EXCLUDE="Maildir/.notmuch/hooks/* Maildir/.notmuch/xapian/*"
Very similar to the normal profile, except mails get stored in the
already existing Maildir/.register/
and different SSH profile and
translation rules are used. The new SSH profile is basically identical
to the previous one:
# wrapper for smd
Host smd-server-register
Hostname imap.anarc.at
BatchMode yes
Compression yes
User register
IdentitiesOnly yes
IdentityFile ~/.ssh/id_ed25519_smd
Then we need to ignore the register folder in the normal configuration:
diff --git a/.smd/config.default b/.smd/config.default
index c42e3d0..74a8b54 100644
--- a/.smd/config.default
+++ b/.smd/config.default
@@ -59,7 +59,7 @@ TRANSLATOR_RL="smd-translate -m move -d RL default"
# EXCLUDE_LOCAL="Mail/spam Mail/trash"
# EXCLUDE_REMOTE="OtherMail/with%20spaces"
#EXCLUDE="Maildir/.notmuch/hooks/* Maildir/.notmuch/xapian/*"
-EXCLUDE="Maildir/.notmuch/hooks/* Maildir/.notmuch/xapian/*"
+EXCLUDE="Maildir/.notmuch/hooks/* Maildir/.notmuch/xapian/* Maildir/.register/*"
#EXCLUDE_LOCAL="$MAILBOX_LOCAL/.notmuch/hooks/* $MAILBOX_LOCAL/.notmuch/xapian/*"
#EXCLUDE_REMOTE="$MAILBOX_REMOTE/.notmuch/hooks/* $MAILBOX_REMOTE/.notmuch/xapian/*"
#EXCLUDE_REMOTE="Maildir/Koumbit Maildir/Koumbit* Maildir/Koumbit/* Maildir/Koumbit.INBOX.Archives/ Maildir/Koumbit.INBOX.Archives.2012/ Maildir/.notmuch/hooks/* Maildir/.notmuch/xapian/*"
And finally we add the new profile to the systemd services:
diff --git a/.config/systemd/user/smd-pull.service b/.config/systemd/user/smd-pull.service
index a841306..498391d 100644
--- a/.config/systemd/user/smd-pull.service
+++ b/.config/systemd/user/smd-pull.service
@@ -8,6 +8,7 @@ ConditionHost=!marcos
Type=oneshot
# --show-tags gives email counts
ExecStart=/usr/bin/smd-pull --show-tags
+ExecStart=/usr/bin/smd-pull --show-tags register
[Install]
WantedBy=multi-user.target
diff --git a/.config/systemd/user/smd-push.service b/.config/systemd/user/smd-push.service
index 10d53c7..caa588e 100644
--- a/.config/systemd/user/smd-push.service
+++ b/.config/systemd/user/smd-push.service
@@ -8,6 +8,7 @@ ConditionHost=!marcos
Type=oneshot
# --show-tags gives email counts
ExecStart=/usr/bin/smd-push --show-tags
+ExecStart=/usr/bin/smd-push --show-tags register
[Install]
WantedBy=multi-user.target
That's about it on the client side. On the server, the user is created with a locked password the mailbox moved over:
adduser --disabled-password register
mv ~anarcat/Maildir/.register/ ~register/Maildir/
chown -R register:register Maildir/
The SSH authentication key is added to .ssh/authorized_keys
, and the
alias is reversed:
--- a/aliases
+++ b/aliases
@@ -24,7 +24,7 @@ spamtrap: anarcat
spampd: anarcat
junk: anarcat
devnull: /dev/null
-register: anarcat+register
+anarcat+register: register
# various sandboxes
anarcat-irc: anarcat
... and the email is also added to
/etc/postgrey/whitelist_recipients
.
That's it: I now have a hardened email service! Of course there are other ways to harden an email address. On-disk encryption comes to mind but that only works with password-based authentication from what I understand, which is something I want to avoid to remove bruteforce attacks.
Your advice and comments are of course very welcome, as usual
I would suggest
chmod 0700 ~register/Maildir/
, assuming it wasn't already non-world-readable.(I checked my own mail server and saw that some subfolders inside my ~/Maildir were world-readable for some reason. No idea why -- should I blame dovecot? My own backup/restore procedures? Anyway it's not too scary: the main ~/Maildir is 0700. But that protection goes away when you
mv
it elsewhere.)That's good advice! As it turns out, the directory was already world/group unreadable, but that's always a good thing to check.
Dovecot should definitely do the right thing here. If it doesn't, that's a serious bug, in my opinion. That folders within the
Maildir
folder are world-readable is problematic as well, but less so if the parent directory is not executable.It's possible backup/restore procedure mess with your permissions. Some software, like git for example, are quite bad at handling read-write permissions (git only tracks the executable bit). But stuff like tar and most other backup software should handle this correctly. rsync is an interesting exception in that, by default, it doesn't synchronize mode and you need to give it a flurry of flags (or just
-a
or is it-aA
or maybe-aAH
? ha ha! you never know!) to have it do the right thing.Finally,
mv
should be safe. Whilecp
doesn't preserve mode by default (that's what-p
is for),mv
does preserve mode, even when moving across devices, strangely.