Sort out your SSH configs
Secure Server
SSH and sFTP hold several hidden treasures within their config files that you might not know about, especially if you are a new sys admin. Even if you have been using them for a while, a review of some of their features might be useful.
Back in 1995, SSH (Secure Shell) was originally freeware but became increasingly proprietary with each new release. From the ground up, SSH was designed to offer different levels of encryption. Since its inception, several open source versions have surfaced, including one of the most popular implementations in 1999: OpenSSH.
In this article, I consider that SSH is focused more on creating a secure tunnel between hosts and that sFTP is a different service or protocol that sits as a subsystem of SSH, specifically for transferring files. In addition to running through a few of the config options available to SSH and sFTP when acting as servers, I will also look at one of the most network-efficient, client-side SSH protocols.
As an example, I use a stock OpenSSH server and client install on a Debian box; however, the build should suit other flavors of Linux. Although doing so is less common, you can use SSH and sFTP on Windows servers, too, and the configuration applies in most cases. I will also mention a few pointers needed for an SSH installation to get us going.
Ssshhh
Most types of servers listen for inbound connections. Upon authentication – and assuming it's set to ignore non-authenticated logins – the server then gives access to resources held by that server (or potentially other servers sitting either behind it or local to it).
After a client connects to the listening SSH daemon (server), it checks that a number of prerequisites have been satisfied. If everything is copacetic, on a Debian box the PAM (pluggable authentication module) authentication system receives a call to arms and acts as a conduit between the resources of the operating system and the server.
It's also perfectly possible to enhance SSH and PAM to use two-factor authentication employed in the financial industry. Although I haven't rolled this out, it looks very promising and works by installing a unique code on your smartphone (via a scanned QR code at install time), which you then regenerate each time you want to log in to your server.
The config file can be found at /etc/pam.d/sshd
. As a non-root user, you should take a peek at the file to get an idea of what happens at the PAM level upon authentication. The sshd
file is relatively readable and includes rules about locales and even Message Of The Day settings if you ever want to alter them.
Innards of the Beast
If you navigate to the /etc/ssh
directory and run the ls
command, you should see the daemon's config file, sshd_config
(assuming, of course, that you have already installed the OpenSSH server):
apt-get install openssh-server
Additionally, you should see the client config file ssh_config
, which I'll get to a little later. If you've just installed the SSH server and want to be sure that it's listening, you can use the command
lsof -i :22
which is a quick way of checking ports that are currently open. The output in my case is shown in Listing 1. As you can see, I have two instances of sshd
: one faithfully listening on all iPv4 IP addresses and the other on all IPv6 IP addresses.
Listing 1: Checking Open Ports
chris@DebianBox:~# lsof -i :22 COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME sshd 3328 root 3r IPv4 33323 0t0 TCP *:ssh (LISTEN) sshd 3328 root 4u IPv6 33325 0t0 TCP *:ssh (LISTEN)
Rather than discuss each and every configuration option, I'll just describe the salient changes I would suggest making. Now would be a good time to make a copy of the original file and then read it with the less
command,
cp /etc/ssh/sshd_config ~ less /etc/ssh/sshd_config
keeping the copy somewhere safe for reference.
A Stitch In Time Saves Nine
As the saying goes, it's better to make a tiny fix today than to give yourself much more work later. Thus, the very first thing I do with a new SSH server install is entirely because of experiencing repeated irritation with a quirk in the past, and that's to disable DNS lookups.
At connection time, the listening daemon will quite rightly log the IP address that's connecting and usually by default try to perform a Reverse DNS Lookup to garnish its logs with a useful hostname.
Sadly, on slow connections, any servers without adequate DNS resolvers set up and IP addresses configured without a proper reverse DNS entry present problems. Waiting for this non-essential DNS lookup to complete can be interminably painful, so the very first thing I do with a new SSH server install is disable DNS lookups. In /etc/sshd_config
, you can add the following line near the bottom,
UseDNS no
then reload the service's config straight away:
# service ssh reload
At the end of my /var/log/auth.log
file I now see the lines shown in Listing 2 indicating that the reload was a success and completed without errors.
Listing 2: /var/log/auth.log
Aug 19 18:10:43 localhost sshd[3328]: Received SIGHUP; restarting. Aug 19 18:10:43 localhost sshd[3328]: Server listening on 0.0.0.0 port 22. Aug 19 18:10:43 localhost sshd[3328]: Server listening on :: port 22.
Not on the List
The next thing I'll discuss is disabling root logins and letting as few users as possible log in remotely over SSH, which is imperative to securing your SSH installation.
A word of warning though: Make sure you have access to whichever less privileged users you have chosen to allow to log in before restarting the server, so you don't lock yourself out.
Disabling root logins can be set in the /etc/sshd_config
file by adding
PermitRootLogin no
or by changing yes
to no
if that line already exists. The next entry likely doesn't exist, so add it to the top of the file to help with troubleshooting in the future; you separate users with spaces. Here, I permit four users to log in over SSH:
AllowUsers steven daniel philippe raheem
Additionally you can control access with AllowGroups
, DenyGroups
, and DenyUsers
. Now if you're sure you can use one of those login accounts, you can reload the daemon as before.
Once I am confident that I can get back into the server remotely, I move the server off the now ill-fated port 22 to something less obvious, such as 2222, which will limit the number of automated port scans testing my security.
This step is simple (but remember which port you choose!) and just needs this change:
Port 2222
Again, simply reload the service and see if you can get back into your server:
ssh -p2222 chrisbinnie@DebianBox.tld
When you are changing SSH configs, you should keep an existing SSH console open. Then, if you make a mistake, you can try to get into your server via the older login session after setting the changes live. It's not infallible, but it works most of the time.
As I wrote in a piece about TCP Wrappers [1], I won't consider running any SSH public-facing instance without TCP Wrappers enabled (even with firewalls), and I ardently recommend you use them.
Versions
OpenSSL, from which OpenSSH receives its clever encryption capabilities, has received inordinate amounts of bad press. In brief, the Internet at large has become to rely on OpenSSL heavily since its predecessor, Telnet, was put in a bad light, but as long as you subscribe to the pertinent security alert mailing lists and patch your servers in a timely manner, you should be out of harm's reach.
That said, many users thought some issues remained unresolved in SSH version 1 (SSH-1); therefore, it is best practice to force your SSH server to insist, without fail, that connecting clients always use at least version 2 (SSH-2) by putting
Protocol 2
in /etc/ssh/sshd_config.
It's a simple change and most likely only alienates older clients or those limited by connectivity or hardware.
In almost all cases any public-facing daemons that you run should hide their banners. By that, I mean you need to avoid advertising which server version is being used, in case of exploits specific to that version. Sadly, however, with SSH you need to recompile the OpenSSH package from source to achieve this, which is time consuming.
Thankfully, this threat is removed if TCP Wrappers are enabled, because the public will not even be able to get to the part of the connection that displays a banner; only your explicitly allowed IP addresses present in /etc/hosts.allow
can get that far.
Another useful precaution is to kick people off the server who have been idle for 20 minutes (i.e., 1,200 seconds):
ClientAliveInterval 1200 ClientAliveCountMax 0
Also, mistakes happen, so it's important to stop accidental connections:
PermitEmptyPasswords no
This entry can be crucial, and I hope self-evident.
sFTP
Although you probably don't mind letting users upload files to their home directories, how do you keep them off the rest of your filesystem so the server keeps running?
One super-simple OpenSSH config entry fixes this perennial sys admin problem. First, make sure the /home
directory is owned by root:
chown root:root /home
At the foot of the /etc/ssh/sshd_config
file, then add the following lines (commenting out the other Subsystem
entry as you do with a hash symbol):
Subsystem sftp internal-sftp Match User chrisbinnie ChrootDirectory /home AllowTCPForwarding no X11Forwarding no ForceCommand internal-sftp
Because this change is not very strict and is relatively forgiving, I'm slightly reluctant to call it a jail or chroot.
The chroot config shows that any user named chrisbinnie
will be dropped to the /home
directory at login and only be able to write files to their home directory (i.e., /home/chrisbinnie
). The Match User
can be changed to Match Group
, which might allow any user in a group (e.g., uploaders
) to write to their directories, too. To see if the setup works, restart SSH now.
The one downside to this simple chroot
config is that users can list the files in other user's home directories. However, you can fix this problem by changing the permissions of each user's home directory with:
chmod 700 /home/chrisbinnie
Make sure you repeat it for any home directories you want kept private in this scenario.
Clients Come First
Because I'm not moving credit card data or anything really sensitive between server and client on my SSH sessions, I am more than comfortable reducing the level of encryption slightly to ensure faster network access. I don't make this change in the /etc/ssh/sshd_server
config file but in the /etc/ssh/ssh_config
client file on my workstation and laptop.
Note that the daemon filename lacks the usual letter d in this case. I append these lines to the foot of that file:
Compression yes Cipher blowfish Ciphers blowfish-cbc,aes128-cbc,3des-cbc,\ cast128-cbc,arcfour,aes192-cbc,aes256-cbc
For once, you don't have to restart the server; just launch a new session to make sure it works. These lines should speed up your console sessions on slow connections, such as when using dial-up or GPRS when you're on the move.
Conclusion
In this article, I have barely scratched the surface of SSH's capabilities, and I haven't even looked at certificate-based logins for automation, powerful port forwarding, X11 forwarding, and the numerous other highly useful features, such as two-step authentication.
Even when using an almost out-of-the-box install, it's easy to see why SSH is a stalwart of the Internet today. I hope this insight will inspire newcomers to delve deeper into some of its other useful features.