Resume emails, part 4: The finale, with webmail & everything after


Aurich Lawson

You’ve all put in a lot of effort to get there: we have a functioning and secure mail server that does a good job of ignoring or eliminating spam emails before they reach your inbox. We have everything in place to ensure the delivery of the mail we send; we have OpenDKIM up and running, and we have the DNS properly configured (including reverse lookups!).

We could stop here and declare success. After all, you can put your email account name and password into your email app or smartphone and send and receive emails. You can easily add new accounts. Best of all, you can easily add aliases, so creating “[email protected]” and using it on a skeevy website that requires email registration, then removing the alias only takes a few seconds.

But are there additional steps we can take to increase safety? What about one-time passwords or two-factor authentication? What about adding a webmail front-end so that we can access our email from a browser? What about push notifications or the calendar? How about letting users set and change their own email passwords? What else can we add to our server and what other configuration paths could we take to do things differently?

We will answer all these questions in this last part.

Postscreen and additional filtering

The Postfix configuration that we put in place in parts 1-3 is quite aggressive. We refuse to communicate with other mail servers that do nothing exactly law; In addition, if you have implemented the Sieve filtering rules that I presented in part 2, we are too discard mail without properly formed message IDs. However, we have not specifically implemented DNS-based black hole list checking. We will do it now.

DNS black hole lists – which you’ll see referred to as DNSRBL, for “DNS Real-Time Black Hole Lists” – are lists maintained by various entities, certain companies and individuals, filled with IP addresses or ranges of addresses. The IP the list maintainer believes the spam to originate from. Different RBLs all have their own criteria for listing an address, and many of them are notoriously hard to come by. disabled once you are listed. Much of the work we did in parts 2 and 3 was to keep our own servers behaving properly and not ending up on one or more of these blacklists.

SpamAssassin (which we configured in part 3) already checks many DNSRBLs as part of its default configuration and notes emails appropriately if the sender’s address is on one or more of them. , but we’re going to take it a step further here and have Postfix reject entirely list-based messages. We will do this by activating a feature of Postfix called postscreen.

Postscreen does a whole bunch of other things as well, all in an effort to separate legitimate mail senders from spammers. Out of the box with very little effort, postscreen implements a number of checks on incoming email to ensure that remote servers are configured as normal and spam free; it also offers more in-depth checks, but we’ll leave them alone, as they may delay receiving emails (or decline them all together).

Postscreen as a whole involves a number of additional Postfix generated processes working on incoming connections before the sptmd process accepts that connection. This means that in order for the postscreen to work, we must first make changes to master.cf, because this configuration file controls how the Postfix master process manages all of its separate daemons and utilities. Open up master.cf; at the start of the file you should see this:

smtp       inet  n       -       -       -       -       smtpd
#smtp      inet  n       -       -       -       1       postscreen
#smtpd     pass  -       -       -       -       -       smtpd
#dnsblog   unix  -       -       -       -       0       dnsblog
#tlsproxy  unix  -       -       -       -       0       tlsproxy
submission inet  n       -       -       -       -       smtpd

We want to comment on the first smtp line, then uncomment the four commented lines, so that we end up with this:

#smtp       inet  n       -       -       -       -       smtpd
smtp       inet  n       -       -       -       1       postscreen
smtpd      pass  -       -       -       -       -       smtpd
dnsblog    unix  -       -       -       -       0       dnsblog
tlsproxy   unix  -       -       -       -       0       tlsproxy
submission inet  n       -       -       -       -       smtpd

If these lines are missing, you will want to add them near the top of master.cf. These lines open the appropriate local ports and create the appropriate Unix sockets for the post-screen process, which will involve handling TLS connections, DNS lookups, and remote blacklist checking.

After that, we also need to make some additions to main.cf to tell Postfix to actually use the postscreen, as well as what remote DNS blacklists we want to check and which senders will be excluded from the postscreen check. So open main.cf for editing and add the following at the bottom:

postscreen_greet_action = enforce
postscreen_dnsbl_action = enforce
postscreen_access_list = permit_mynetworks
postscreen_dnsbl_sites = zen.spamhaus.org, b.barracudacentral.org,
	bl.spamcop.net

The first two parameters implement the filtering part of the postscreen functionality, telling it that we want to enforce non-spam login behavior (and not accept connections from clients who try to bypass the process to deliver spam faster. ) and activate the DNS blacklist verification. The following parameter excludes your mynetworks variable content of post-screen check (which will prevent LAN clients from being post-screen). Finally, the last parameter adds three DNSRBLs to the postscreen checklist.

You can specify as many or as few RBLs as you want; there are many choices. In addition, you can use the postscreen_dnsbl_threshold setting to control the number of lists a sender must be on for the postscreen to reject the email; if you want to be really fancy, you can also assign different weights to your blocklists so that you are on one more “account” than the other. The Postfix documentation has more information on how to configure this.

Restart Postfix with sudo service postfix restart to bring your changes to life. There you go, the postscreen is now active. If you want to see it in action, email yourself from an external account and watch your /var/log/mail.log to file:

Postscreen, does its job.
Enlarge / Postscreen, does its job.

Another safety tip: speed limiting with iptables

Postfix will automatically limit the rate of connection attempts – this is what the postfix anvil process is for. However, rather than changing the default configuration further, we can rely on a much more powerful and flexible tool to do our rate limiting: iptables.

Iptables allows you to define rules that will affect the behavior of the operating system kernel firewall. It has an extraordinarily flexible (and extraordinarily complex) level of configuration, and so rather than giving an exhaustive iptables tutorial, we’ll very quickly explain how to use it to suppress connections from spammers who spam too loudly.

Note that when implementing iptables here above the postscreen, it’s a bit like wearing a belt with suspenders: it can be a bit of a stretch. However, if you find yourself in a situation where you can’t (or don’t want to) implement postscreen or some other rate limiting solution, iptables can easily do the trick. He’s very, very good at what he does.

What it is not, however, is friendly to inexperienced users. The first thing we need to do is install a quick program to automatically save your running iptables configuration on shutdown and reapply it on startup (iptables doesn’t do this on its own). So, run the following command:

aptitude install iptables-persistent

As part of the rapid iptables-persistent setup, you will be asked if you want to save your current set of iptables rules; you probably don’t have one, but say yes anyway.

Then go to /etc/iptables. It’s here that iptables-persistent keeps saved copies of your firewall rules. There should be a file named rules.v4 in the directory, containing your IPv4 specific firewall rules (there is probably also a rules.v6 file, which we can ignore).

Your rules.v4 file should contain very little. If you haven’t explicitly defined any iptables rules, it should look like this:

*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
COMMIT

If it does not, and instead contains one or more rules, then you should probably skip this section unless you know exactly what the existing rules are for and why they are there. If you are comfortable with the syntax of iptables, you can graft our configuration onto your existing rules, but this will require a bit of reconfiguration; if you don’t know exactly how to do it already, you should stop and move on to the next section.

If your rules are indeed empty, with only three “accept” strings defined, then we can continue. Delete the contents of the file and replace it with the following:

*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
:LOG_AND_DROP - [0:0]
-A INPUT -s 192.168.0.0/24 -i eth0 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 993 -m state --state NEW -m recent --set --name imapssl --rsource
-A INPUT -p tcp -m tcp --dport 993 -m state --state NEW -m recent --update --seconds 10 --hitcount 20 --name imapssl --rsource -j LOG_AND_DROP
-A INPUT -p tcp -m tcp --dport 993 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 587 -m state --state NEW -m recent --set --name imap --rsource
-A INPUT -p tcp -m tcp --dport 587 -m state --state NEW -m recent --update --seconds 10 --hitcount 20 --name imap --rsource -j LOG_AND_DROP
-A INPUT -p tcp -m tcp --dport 587 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 465 -m state --state NEW -m recent --set --name smtps --rsource
-A INPUT -p tcp -m tcp --dport 465 -m state --state NEW -m recent --update --seconds 10 --hitcount 20 --name smtps --rsource -j LOG_AND_DROP
-A INPUT -p tcp -m tcp --dport 465 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 25 -m state --state NEW -m recent --set --name smtp --rsource
-A INPUT -p tcp -m tcp --dport 25 -m state --state NEW -m recent --update --seconds 10 --hitcount 20 --name smtp --rsource -j LOG_AND_DROP
-A INPUT -p tcp -m tcp --dport 25 -j ACCEPT
-A LOG_AND_DROP -j LOG --log-prefix "iptables deny: " --log-level 7
-A LOG_AND_DROP -j DROP
COMMIT

Make sure to change “192.168.0.0/24” to point to your LAN subnet (or just to your own server’s IP address if you are on EC2 or other shared hosting). We create a new chain “LOG_AND_DROP” and instruct iptables to keep track of incoming connections on TCP ports 993, 587, 465 and 25. If a client reaches these ports more than 20 times in 10 seconds, iptables will disable the barrier. fire that client and remove all traffic from it until it stops sending.

The 20 connection and 10 second limits can be adjusted to your liking, although counting more connections may require changing some kernel parameters.

After registering and exiting rules.v4, you can activate the rules with the iptables-restore command, like this:

iptables-restore rules.v4

To see a list of active iptables rules, you can run iptables -L.

Now on to webmail!