Security in Three Ds: Detect, Decide and Deny
Whenever a server is accessible via the Internet, it's a safe bet that hackers will be trying to access it. Just look at the SSH logs for any server you use, and you'll surely find lots of "authentication failure" lines, originating from IPs that have nothing to do with you or your business. Brute-force attempts (such as "dictionary attacks") try different passwords over and over to try to get into your box, and there's always a chance that they eventually will succeed. Thus, it's a good idea to apply these "three Ds" for your security: detect intruder attempts, decide when they've gone "over the top" (past what would be acceptable for honest-to-goodness typing mistakes), and deny them access at least for a (longish!) while.
Several tools manage this kind of monitoring (see the Resources section). In this article, I describe installing, configuring and running DenyHosts. With it, you'll have a running background dæmon that will check your system continuously for access attempts, decide if they look unsafe, block them and inform you. DenyHosts even can be configured to share information with other servers, so whenever a hacker is detected on one system, it will be blocked on other systems too.
Installation and Configuration
DenyHosts' current version is 2.6 (from June 2013). It is a Python script, and you probably already have that language installed. If not, you'll need to use your distribution package tool to set it up first. You need version 2.3 or higher.
Many distributions already provide a "denyhosts" package, and using
your system tools is the simplest installation method. For example, type
sudo apt-get install denyhosts for Ubuntu,
sudo yum install
denyhosts for Red Hat or
sudo zypper install
OpenSUSE. Otherwise, you can download the tar.gz file (see
Resources) and then do:
$ tar zxvf DenyHosts-2.6.tar.gz $ cd DenyHosts-2.6 $ sudo python setup.py install
No matter how you install DenyHosts, a /usr/share/denyhosts will be
created, with all configuration and script files within it. You'll
want to edit the denyhosts.cfg file to configure DenyHosts for your
environment. (Should that file not exist, do
denyhosts.cfg to get a basic sample configuration file to start
with.) Blank lines and lines starting with # are ignored. There
are plenty of comments to help you understand each configuration item,
but pay close attention to some key items (Table 1).
|SECURE_LOG||Location of the access log: /var/log/secure for Red Hat, /var/log/auth.log for Ubuntu or OpenSUSE, and so on. DenyHosts will scan this file to detect possible hacking attempts.|
|HOSTS_DENY||Location of the restricted host file, usually /etc/hosts.deny. DenyHosts will add lines to this file whenever a possible intruder is detected.|
|LOCK_FILE||A file path and name: this file is created when DenyHosts starts and is deleted when it exits. If you try to run DenyHosts, and this file exists, Denyhosts will exit immediately, preventing more than one instance from running at the same time.|
|WORK_DIR||The directory DenyHosts will use for its own data.|
|DAEMON_LOG||Location of the log file that DenyHosts will use to report its status when run in dæmon mode.|
|DAEMON_SLEEP||Amount of time that DenyHosts will wait before checking the SECURE_LOG.|
|DAEMON_PURGE||Amount of time between purges of old entries in HOSTS_DENY (see PURGE_DENY below).|
|BLOCK_SERVICE||What service should be blocked in HOSTS_DENY. Set it to "sshd" to disable only SSH access or to "ALL" to block every attempt from the remote host.|
|ADMIN_EMAIL||Address to which e-mail messages regarding blocked hosts and suspicious logins should be sent. If you set this to a non-blank value, you'll need to set SMTP_HOST, SMTP_PORT, SMTP_USERNAME and SMTP_PASSWORD as well, so DenyHosts can connect to your mail server.|
|DENY_THRESHOLD_INVALID, DENY_THRESHOLD_VALID and DENY_THRESHOLD_ROOT||After how many failed login attempts DenyHosts should block a host (due to wrong user account names, correct user names but wrong passwords or failed root access attempts). But, you shouldn't allow remote root access at all; see the Resources section for some suggestions about this!|
|RESET_ON_SUCCESS||If set to "yes", the failed count for the server will be reset to zero after a successful login.|
|AGE_RESET_INVALID, AGE_RESET_VALID and AGE_RESET_ROOT||After what period of time the failed count for the host will be reset to 0 for wrong user account attempts, wrong password attempts and root access attempts.|
|PURGE_DENY||Time after which HOSTS_DENY entries will be purged if you run DenyHosts with the --purge flag. I usually go with "1w" (one week), but you can leave it blank (never purge), or you can use minutes, hours, days or weeks.|
|PURGE_THRESHOLD||How many times a host can be purged until DenyHosts decides it's a confirmed risk and stops purging it, thus disabling it forever. Set this to zero to disable the feature.|
As an extra assurance that you won't be banned from your own server, you
should edit /etc/hosts.allow and add a line for each IP you use, in a
sshd: 188.8.131.52. DenyHosts has a file of its own,
allowed-hosts, that defines IPs (one per line) that won't ever
Now you are ready to start running DenyHosts—let's move on to that!
You can run DenyHosts periodically (let's say as a cron job),
but it's better to run it in dæmon mode. DenyHosts then will run in the
background, checking the access logs to detect possible intruders. For
this, you need to create an extra configuration file by executing
cp daemon-control-dist daemon-control. Then, edit the file to
make sure its three parameters are defined correctly (Table 2).
|DENYHOSTS_BIN||Should point to the denyhosts.py script.|
|DENYHOSTS_CFG||Should point to the denyhosts.cfg configuration file.|
|DENYHOSTS_LOCK||Should point to the same file as LOCK_FILE in Table 1.|
Then, all you need to do is start the service with
/etc/init.d/denyhosts restart or
depending on your server, and you are set. From that moment on, DenyHosts
will monitor login attempts, and upon detection of oft-repeated
failures, it will decide to deny all access to the would-be intruder
Just in case, you also should set DenyHosts to
start automatically on reboot—doing
is a way to manage this.
Figure 1. DenyHosts monitors the access logs and eventually locks out the hacker's host.
Once DenyHosts is running, it will monitor the logs, and after detecting repeated failed login attempts, when certain thresholds are reached, it will decide to block the remote IP to deny the would-be hacker all possibilities of connection. For example, I deliberately entered wrong passwords time after time, and eventually I was blocked (Figure 1 also explains why DenyHosts needs to run as root; otherwise, it wouldn't be able to edit the hosts.deny file):
> ssh firstname.lastname@example.org email@example.com's password: Permission denied, please try again. firstname.lastname@example.org's password: Permission denied, please try again. email@example.com's password: Permission denied (publickey,password). > ssh firstname.lastname@example.org email@example.com's password: Permission denied, please try again. firstname.lastname@example.org's password: Permission denied, please try again. email@example.com's password: Permission denied (publickey,password). . . . several attempts, and then... > ssh firstname.lastname@example.org ssh_exchange_identification: read: Connection reset by peer
DenyHosts eventually will lift the restriction (depending on the configuration), but if a valid user somehow managed to get banned from a valid server, you can fix the problem without further delay (see the Forgiving a User sidebar).
Don't Get Locked Out!
It goes without saying, you should test DenyHosts to verify that it's running. Of course, and most important, keep at least an open shell in your server while you do your testing; otherwise, should anything go wrong, you could get locked out of your own IP address, and you'd have a nice problem!
While you try accessing the server from a different machine, you can use
tail -f to monitor both the hosts.deny file and DenyHosts' own log
file (see the HOSTS_DENY and DAEMON_LOG configuration parameters in Table 1). After
a few failed attempts, you should see changes in both files, and you
should be getting an e-mail message as well, confirming that your configuration
DenyHosts provides another service that allows you to share whatever IPs you block with other servers around the world, and vice versa. The idea is simple. If anybody detects that hacking attempts are coming from a certain IP, every server that blocks it without waiting to be attacked is made a bit safer. There are a few parameters you need to consider, as shown in Table 3.
|SYNC_SERVER||To what server you should connect for central synchronization. Currently, xmlrpc.denyhosts.net:9911 is the only available server, but in the future, organizations may install their own synchronizing servers for internal usage.|
|SYNC_INTERVAL||How often to synchronize with the server.|
|SYNC_UPLOAD and SYNC_DOWNLOAD||Whether DenyHosts should upload and download banned IPs; the logical option is YES in both cases.|
|SYNC_DOWNLOAD_THRESHOLD||Download only IPs that have been detected and blocked at least by this number of DenyHosts distinct servers.|
|SYNC_DOWNLOAD_RESILIENCY||Download only IPs that have been detected over this period. The larger this value, the more probable the IP is an actual hacker.|
Sharing this information is usually a good idea, so you can stave off would-be hackers even before they start sniffing at your server. The sharing service currently is free (although donations are accepted), but eventually businesses might be charged for it, as the DenyHosts FAQ states. You can contact the DenyHosts creator to license the server component and run your own sharing server.
No matter how careful, once in a while someone messes up, enters the wrong password too many times and gets banned by DenyHosts. How can you fix this? Once you've decided that the errant user should be forgiven, take the following steps:
Learn the user's current IP so you can enable it again.
Check every file in the WORK_DIR directory (see Table 1), and delete every line in which the IP appears (using
Edit /etc/hosts.deny in the same way.
Now, if the user tries again, access should be granted. Don't be tempted to skip step 3. If you do, as soon as you restart DenyHosts, the remote IP will be blocked again!
Security is a 24/7 job, and all the tools that you can add into the mix go a long way toward making your server secure. DenyHosts is easy to install, and it provides quick detection of hacking attempts, blocking remote hackers and impeding brute-force attacks. Although it's not a "silver bullet" solution for all possible intruder problems, it's a worthy tool that you should add to your security toolkit. Give it a try!
You can find DenyHosts at http://denyhosts.sourceforge.net, and download it from the project's site at http://sourceforge.net/projects/denyhosts. Several common questions are answered at http://denyhosts.sourceforge.net/faq.html.
I've previously written other articles on security measures for Linux Journal: "PAM—Securing Linux Boxes Everywhere" (January 2009), "Implement Port-Knocking Security with knockd" (January 2010) and "More Secure SSH Connections" (January 2014).