Raspberry Pi boards (or any of the many similar boards) are handy to leave at odd places to talk to the network and collect data, control things, or do whatever other tasks you need a tiny fanless computer to do. Of course, any time you have a computer on a network, you are inviting hackers (and not our kind of hackers) to break in.
We recently looked at how to tunnel ssh using a reverse proxy via Pagekite so you can connect to a Pi even through firewalls and at dynamic IP addresses. How do you stop a bad guy from trying to log in repeatedly until they have access? This can work on any Linux machine, but for this tutorial I’ll use Raspberry Pi as the example device. In all cases, knowing how to set up adequate ssh security is paramount for anything you drop onto a network.
Better than Password Security
Experts tell you to use a good password. However, with ssh, the best method is to disallow passwords completely. To make this work, you need to create a private and public certificate on the machine you want to use to connect. Then you copy the public key over to the Raspberry Pi. Once it is set up, your ssh client will automatically authenticate to the server. That’s great if you always log in using the same machine and you never lose your keys.
You need to create a personal key pair if you haven’t already. You can use the ssh-keygen command to do that on Linux. You can require a passphrase to unlock the key or, if you are sure only you have access to your machine, you can leave it blank.
Once you have the key it is easy to send the public key over to the server with the ssh-copy-id command. For example:
ssh-copy-id [email protected]
You log in with your password one last time and the command copies your public key to the server. From then on, when you use ssh on that host, you’ll be automatically authenticated. Very handy.
Once you have keys set up, you can disable using regular passwords by editing /etc/ssh/sshd_config. You need the following settings:
ChallengeResponseAuthentication no PasswordAuthentication no UsePAM no
That prevents anyone from breaking in by brute force guessing of passwords. It also makes it harder to set up new users or log in from a new computer.
Save the Passwords; Use Two Types
For those reasons, it is not always a good idea to turn off passwords. A better idea is to use two-factor authentication. That requires you to enter a password and also a “one time” verification code. Where do you get that code?
There are several options, but the one I’ll use is from the Google Authenticator application. You can get the application for Apple devices, Blackberries, and-of course-Android devices. You install it in the usual way for your device. The trick is how to make the ssh server on the Pi use it.
Luckily the Raspian repos have a package called libpam-google-authenticator that will do the trick. Installing it with apt-get is only part of the trick, though. You need two things. First, you need to set up your account.
Set Up a Google Authenticator Account
To set up your account, you need to log into your Pi and issue the command google-authenticator. The program will ask you a few questions and then generate a URL that will show you a QR code. It will also provide you a numeric code. You can use either of these to set up your phone. The command will also provide you a few one-time scratch codes you need to save in case you lose your authenticator device. You need to do this for any user ID that can log in via ssh (even ones where you normally use a certificate).
Tell Your Pi to Require Two-Factor Login
The other part of the puzzle requires you to make changes to /etc/pam.d/sshd and /etc/ssh/sshd_config. The first line of /etc/pam.d/sshd should be:
auth required pam_google_authenticator.so
In /etc/ssh/sshd_config you need to make sure passwords are on:
ChallengeResponseAuthentication yes PasswordAuthentication yes UsePAM yes
Just make sure you don’t mess anything up. Losing the ssh server could stop you from being able to access the machine. I haven’t messed one up yet, but the advice I hear is to keep an ssh session open while you restart the ssh server (/etc/init.d/sshd restart) so if something goes wrong, you’ll still have a shell prompt open. You might also consider running:
This will verify your configuration before you pull the trigger.
By the way, if you already use certificates to log in, this won’t change anything for you. The certificate authentication takes priority over passwords. That does make it tricky to test your setup. You can force ssh not to use your certificate like this:
ssh -o PreferredAuthentications=password -o PubkeyAuthentication=no [email protected]
Even for accounts where you use certificates, adding the two-factor log in will prevent brute force attacks on your password, so be sure to set up for all accounts you can use over ssh.
There are several other things you can do to help secure your ssh connection:
- Disallow root logins (edit the PermitRootLogin line in /etc/ssh/sshd_config; you can use sudo from a normal account if you want to become root)
- Use a non-standard ssh port (edit port in sshd_config)
- Consider installing fail2ban which will block IP addresses that exhibit suspicious behavior
- Disallow any users that don’t need ssh access (use AllowUsers or DenyUsers in the sshd_config file)
- Set PermitEmptyPasswords in sshd_config to ‘no’
Not everyone will agree with disallowing root logins. However, empirically, a lot of attacks will try logging in as root since virtually every Linux system has that account. It is harder for a random attacker to know that my user ID is WetSnoopy.
There are many other techniques ranging from port knocking to locking users to their home directories. You can rate limit connection attempts on the ssh port. Only you can decide how much security is enough. After all, you lock up your cash box better than you lock up your supply closet. However, convenient and free two-factor authentication can add a high level of security to your Raspberry Pi or other Linux-based projects. If you are really concerned, by the way, you can also force two-factor for accessing sudo, as well.