Our SSH configuration is a lot more secure than it used to be, but we can still make it better. Here are a few little tricks that you might not have seen elsewhere.
When you SSH into a server in the normal manner, as we’ve been doing, you can only run text-mode programs. If you try to remotely run any GUI-based program, such as Firefox, you’ll get an error message. But, when you open the sshd_config file of pretty much any Linux distribution, you’ll see this line:
This means that with the right option switch, you can remotely run GUI-based programs. Assuming that you’re logging into a machine that has a graphical desktop environment installed, you can use either the -Y or the -X option when logging in, like so:
ssh -X firstname.lastname@example.org or ssh -Y email@example.com
The problem here is that the X11 protocol, which powers graphical desktop environments on most Linux and Unix systems, has a few security weaknesses that make it somewhat dangerous to use remotely. The bad guys have ways of using it to compromise an entire system. Your best bet is to disable it by changing the X11Forwarding line to the following:
As usual, restart the SSH service to make it read in the new configuration.
Now that you know about X11 forwarding, let’s dig some tunnels.
SSH tunneling, or as it’s sometimes called, SSH port forwarding, is a handy way to protect non-secure protocols. For example, by tunneling normal HTTP through an SSH tunnel, you can access a non-secure website in a secure fashion. To do this, you would do the following:
sudo ssh -L 80:localhost:80 firstname.lastname@example.org
I had to use sudo here because all network ports below port 1024 are privileged ports. If I were to change the web server configuration to listen on a non-privileged high-number port, I wouldn’t need sudo.
Now, to connect to this site in a secure manner, I can just open the web browser on my local machine and type in the following URL:
Yeah, it seems strange to access a remote machine by typing in localhost, but that’s the designator I used when I logged in with SSH. I could have used another name, but localhost is the name you traditionally see in SSH tutorials, so I’m following suit here. Now, as soon as I log out of the SSH session, my connection to the web server will break.
Even though this sounds like a good idea, it actually creates a security problem. Let’s say that your corporate firewalls are set up to prevent people from going home and remoting into their company workstations. That’s a good thing, right? Now, let’s say that the company firewall has to allow outbound SSH connections. A user could create an SSH tunnel from their company workstation to their computer at another location, then go to that location and create a reverse tunnel back to their company workstation. So, if it isn’t possible to block outgoing SSH traffic at the firewall, then your best bet is to disable SSH tunneling. In your sshd_config file, ensure that you have lines that look like this:
AllowTcpForwarding no AllowStreamLocalForwarding no GatewayPorts no PermitTunnel no
Restart the SSH service, as always. Now, port tunneling will be disabled.
Now that you know how to disable SSH tunneling, let’s talk about changing the default port.
By default, SSH listens on port 22/TCP. If you’ve been around for a while, you’ve surely seen plenty of documentation about how important it is to use some other port in order to make it harder for the bad guys to find your SSH server. But, I must say, this notion is a bit controversial.
In the first place, if you enable key authentication and disable password authentication, then changing the port has limited value. When a scanner bot finds your server and sees that password authentication is disabled, it will just go away and won’t bother you anymore. In the second place, if you were to change the port, the bad guys’ scanning tools can still find it. If you don’t believe me, just go to Shodan.io and search for ssh. In this example, someone thought they were smart by changing to port 2211:
Yeah, smarty-pants. That didn’t hide things so well, now, did it?
On the other hand, security expert Daniel Miessler says that it’s still useful to change the port, in case someone tries to leverage a zero-day exploit against SSH. He recently published the results of an informal experiment that he did, in which he set up a public server that listens for SSH connections to both port 22 and port 24, and observed the number of connection attempts to each port. He said that over a single weekend, there were 18,000 connections to port 22 and only five to port 24. But, although he doesn’t explicitly say, it appears that he left password authentication enabled. To have truly scientifically accurate results, he needs to conduct the same study with password authentication disabled. He also needs to conduct the study on separate servers that have SSH enabled for either port 22 or port 24, instead of having both ports enabled on a single machine. My hunch is that when the scanner bots found that port 22 was open, they didn’t bother to scan for any other open SSH ports.
Anyway, if you do want to change ports, just uncomment the #Port 22 line in sshd_config, and change the port number to whatever you want.
Next, let’s talk about key management.
Earlier, I showed you how to create a pair of keys on your local workstation, and then transfer the public key to a remote server. This allows you to disable username/password authentication on the server, making it much harder for the bad guys to break in. The only problem with this that we didn’t address is that the public key goes into an authorized_keys file that’s in the user’s own home directory. So, the user can manually add extra keys to the file, which would allow the user to log in from other locations besides the one that’s been authorized. And, there’s also the problem of having authorized_keys files all over the place, in every user’s home directory. That makes it a bit hard to keep track of everyone’s keys.
One way to handle this is to move everyone’s authorized_keys file to one central location. Let’s take Vicky, my solid gray kitty. The administrator created an account on the server that she needs to access and allowed her to create and transfer her key to it before disabling password authentication. So, Vicky now has her authorized_keys file in her home directory on that server, as we see can here:
vicky@ubuntu-nftables:~$ cd .ssh vicky@ubuntu-nftables:~/.ssh$ ls -l total 4 -rw------- 1 vicky vicky 233 Oct 3 18:24 authorized_keys vicky@ubuntu-nftables:~/.ssh$
Vicky owns the file, and she has both read and write permissions on it. So, even though she can’t transfer other keys to it the normal way once the administrator has disabled password authentication, she can still transfer key files manually, and manually edit the authorized_keys file to include them. To thwart her efforts, our intrepid administrator will create a directory within the /etc/ssh/ directory to hold everyone’s authorized_keys files, like so:
sudo mkdir /etc/ssh/authorized-keys
Our intrepid administrator’s full admin privileges allow him to log into the root user’s shell, which allows them to go into the directories of all other users:
donnie@ubuntu-nftables:~$ sudo su - [sudo] password for donnie: root@ubuntu-nftables:~# cd /home/vicky/.ssh root@ubuntu-nftables:/home/vicky/.ssh# ls -l total 4 -rw------- 1 vicky vicky 233 Oct 3 18:24 authorized_keys root@ubuntu-nftables:/home/vicky/.ssh#
The next step is to move Vicky’s authorized_keys file to the new location, changing its name to vicky, like so:
root@ubuntu-nftables:/home/vicky/.ssh# mv authorized_keys /etc/ssh/authorized-keys/vicky root@ubuntu-nftables:/home/vicky/.ssh# exit donnie@ubuntu-nftables:~$
Now, we have a bit of a conundrum. As you can see here, the file still belongs to Vicky, and she has both read and write privileges. So, she can still edit the file without any administrator privileges. Removing the write privilege won’t work, because since the file belongs to her, she could just add the write privilege back. Changing ownership to the root user is part of the answer, but that will prevent Vicky from being able to read the file, which will prevent her from logging in. To see the whole solution, let’s see what I’ve already done with my own authorized_keys file:
donnie@ubuntu-nftables:~$ cd /etc/ssh/authorized-keys/ donnie@ubuntu-nftables:/etc/ssh/authorized-keys$ ls -l total 8 -rw------- 1 vicky vicky 233 Oct 3 18:24 vicky -rw-r-----+ 1 root root 406 Oct 3 16:24 donnie donnie@ubuntu-nftables:/etc/ssh/authorized-keys$
The eagle-eyed among you have surely noticed what’s going on with the donnie file. You have seen that I changed ownership to the root user and then added an access control list, as indicated by the + sign. Let’s do the same for Vicky:
donnie@ubuntu-nftables:/etc/ssh/authorized-keys$ sudo chown root: vicky donnie@ubuntu-nftables:/etc/ssh/authorized-keys$ sudo setfacl -m u:vicky:r vicky donnie@ubuntu-nftables:/etc/ssh/authorized-keys$
Looking at the permissions settings, we see that Vicky has read access to the vicky file:
donnie@ubuntu-nftables:/etc/ssh/authorized-keys$ ls -l total 8 -rw-r-----+ 1 root root 406 Oct 3 16:24 donnie -rw-r-----+ 1 root root 233 Oct 3 18:53 vicky donnie@ubuntu-nftables:/etc/ssh/authorized-keys$
While we’re at it, let’s look at her access control list:
donnie@ubuntu-nftables:/etc/ssh/authorized-keys$ getfacl vicky # file: vicky # owner: root # group: root user::rw- user:vicky:r-- group::--- mask::r-- other::--- donnie@ubuntu-nftables:/etc/ssh/authorized-keys$
Vicky can now read the file so that she can log in, but she can’t change it.
The final step is to reconfigure the sshd_config file, and then restart the SSH service. Open the file in your text editor and look for this line:
#AuthorizedKeysFile .ssh/authorized_keys .ssh/authorized_keys2
Change it to this:
The %u at the end of the line is a mini-macro that tells the SSH service to look for a keys file that has the same name as the user who’s logging in. Now, even if the users were to manually create their own authorized_keys files in their own home directories, the SSH service would just ignore them. Another benefit is that having the keys all in one place makes it a bit easier for an administrator to revoke someone’s access, should the need arise.
Be aware that there’s a lot more to managing SSH keys than what I’ve been able to present here. One problem is that while there are a few different free open source software solutions for managing public keys, there aren’t any for managing private keys. A large corporation could have thousands or perhaps even millions of private and public keys in different places. Those keys never expire, so they’ll be around forever unless they get deleted. If the wrong people get hold of a private key, your whole system could become compromised. As much as I hate to say it, your best bet for managing SSH keys is to go with a commercial solution, such as ones from https://www.ssh.com/ and CyberArk.
Head here for CyberArk’s: https://www.cyberark.com/solutions/by-project/ssh-key-security-management/.
Full disclosure: I have no connection with either https://www.ssh.com/ or CyberArk, and receive no payment for telling you about them.
You’ve learned several cool tricks here for beefing up your server security. Now, let’s look at how to create different configurations for different users and groups.
On the server side, you can use the Match User or Match Group directive to set up custom configurations for certain users or groups. To see how it’s done, look at the example at the very bottom of the /etc/ssh/sshd_config file. There, you’ll see the following:
# Match User anoncvs # X11Forwarding no # AllowTcpForwarding no # PermitTTY no # ForceCommand cvs server
Of course, this has no effect since it’s commented out, but that’s okay. Here’s what we see for user anoncvs:
- He can’t do X11 forwarding.
- He can’t do TCP forwarding.
- He won’t have the use of a command Terminal.
- As soon as he logs in, he’ll be starting the Concurrent Versioning Service (CVS) server. By not having use of the Terminal, anoncvs can start the CVS server, but can’t do anything else.
You can set up different configurations for as many users as you need to. Anything that you put in the custom configurations will override the global settings. To set up a custom configuration for a group, just replace Match User with Match Group, and supply a group name instead of a user name.
For a change of pace, let’s look at the client’s end now. This time, we’ll look at a handy trick to help ease the pain of logging into different servers that require different keys or SSH options. All you have to do is go into the .ssh directory in your own home directory and create a config file. To demonstrate this, let’s say that we’ve created either a DNS record or an /etc/hosts file entry for our servers so that we don’t have to remember so many IP addresses.
Let’s also say that we’ve created a separate pair of keys for each server that we need to access. In the ~/.ssh/config file, we can add a stanza that looks something like this:
Host ubuntu-nftables IdentityFile ~/.ssh/unft_id_rsa IdentitiesOnly yes ForwardX11 yes Cipher email@example.com
Here’s the breakdown:
- IdentityFile: This specifies the key that goes with this server.
- IdentitiesOnly yes: If you happen to have more than one key loaded into your session keyring, this forces your client to only use the key that’s specified here.
- ForwardX11 yes: We want this client to use X11 forwarding. (Of course, this will only be effective if the server has been configured to allow it.)
- Cipher firstname.lastname@example.org: We want to use this algorithm, and only this algorithm, to perform our encryption.
To create custom configurations for other hosts, just add a stanza for each one to this file.
After you save the file, you have to change its permissions settings to a value of 600. If you don’t, you’ll get an error when you try to log into any of the servers that are configured in the file.
Now that you know about custom configurations, let’s talk about SFTP, where we’ll make good use of the Match Group directive that we just looked at.