Securing SSH

ssh (Secure SHell) is one of Unix's most basic security features. With ssh, you can make a connection over an encrypted connection from one machine to another. Additionally, ssh's ability to use Port Forwarding lets you make connections to other services through the strong ssh tunnel.

In its default configuration, ssh provides very good security (assuming you use strong passwords). However, there are a few minor tweaks which take minimal time which will increase your security by an order of magnitude.

Instructions given here are based on the Debian Wheezy distribution of Linux, however the basics of ssh cross all Unix platforms (including Apple OSX) and can be done in a similar manner.

Use Public Key Authentication

By default, ssh allows many forms of authentication, including RSA, Public Key, and Password. Of these, Public Key is by far the strongest and should be used wherever possible. There is overhead in that each user must generate an ssh public key pair and the public key generated must be manually copied to the .ssh/authorized_keys file for the user on the remote server. Additionally, the private key must be copied to every workstation from which that user will originate.

Once implemented, the initial login is performed by decrypting the private key on the source. ssh then uses the private key to encrypt the initial connection to the server, sending a message encrypted with that private key which can only be decrypted using the public key on the server. When connected to the server, you are then given the users permissions on the server, without ever knowing the password on that server. To perform a task on the server requiring your server side password (such as sudo), you will need to know the users password on that server.

There are four steps to set a server to use public key encryption.

Create private/public key pair on workstation

You can, of course, reuse an existing key pair if one is already generated. Simply copy your private key to the .ssh/ directory on your workstation. Note: if you are doing this, ensure the .ssh directory and the private key are owned by the user. Also, have the .ssh directory set to permission 755 and the private key file set to 644 at a minimum. I prefer to set the .ssh directory to 700 and the private key file to 600 (no access to either for any but the owner).

If you need to generate your own key pair, use the ssh-keygen program which is installed by default with ssh.

ssh-keygen -t rsa -b 2048

ssh-keygen -t dsa -b 1024

Choose one of the commands above. The first will create an rsa key pair using 2048 bits, which is currently considered sufficient. The key length can be as small as 768 bits, though this is considered very insecure. For very high security, you can increase that to 4096 (ie, -b 4096) but be aware it will take a much longer time to generate the pair.

For dsa, 1024 is the only size allowed as per FIPS 186-2. Any attempt to generate a different sized key for dsa will result in an error.

ssh-keygen will ask for a passphrase to encrypt the private key with. Note, this is a passphrase; it can contain embedded spaces and special characters, and care must be given to ensure this is a very secure phrase (though no checking is performed on complexity). I recommend a minimum of 12 characters, mixing alpha case, numeric digits and special characters.

Note: while you can create a key with an empty passphrase (by simply pressing the enter key when asked for the passphrase), this is strongly discouraged and should only be used in specific environments where it is required.

Once you have entered your passphrase (twice), the private key is encrypted with it. ssh-keygen will then ask where to store the two files (private and public key files), with the default being .ssh/ (which will be created if it does not exist).

Copy public key to server

Looking in the .ssh/ directory, you will see two files, id_rsa and (assuming you chose rsa to generate your key). id_rsa is your private key, and should be treated very securely. Never give your private key to anyone and do not place your private key where others can access it.

Your public key ( however can be freely placed where needed and transmitted over insecure media. You can copy it on a thumb drive, transfer via ftp or email, or even copy from one terminal and paste into another. Its only utility is to decrypt messages encrypted by the private key. See if you would like to know why this is so.

Copy your public key to the server and append it to the file .ssh/authorized_keys in the target user's directory. This file must be set with permissions 644 at a minimum, and I recommend 600. If the file does not exist, create it with those permissions. authorized_keys may have many entries, one per line, each of which will allow a separate private key to gain access, generally used to allow multiple users to connect to one account.

Test Connection

To test the connection, attempt to make an ssh connection from the remote machine to the target. If it asks for a password as normal, there is something wrong; some reason it will not use the public key pair. However, if you get the following prompt:

Enter passphrase for key '/home/user/.ssh/id_rsa': 

 you are connecting using your private key passphrase. Ensure you can connect completely to the server before proceeding with the next step.

Configure ssh server to only allow public key authentication

This step will ensure that no connections can be made except via public key authentication. Thus, you must ensure the Test Connection step completed correctly before proceeding or  you can lock yourself out from the server unless you physically connect from the console (keyboard on the server itself).

Make a backup copy of /etc/ssh/sshd_config.

cp -av /etc/ssh/sshd_config /etc/ssh/

Edit the file /etc/ssh/sshd_config. Find the following lines and modify them as shown. This step must be done as root, and remember you are doing it on the server.

RSAAuthentication no
PubkeyAuthentication yes
RhostsRSAAuthentication no
HostbasedAuthentication no
PermitEmptyPasswords no
ChallengeResponseAuthentication no
PasswordAuthentication no

Note: the final line (PasswordAuthentication) is generally commented out and set to "yes" by default, so you must uncomment it by removing the leading pound sign.

Once you have made the changes above, reload the ssh daemon on the server with

/etc/init.d/ssh reload

Do not log out after doing this! If you log out and find you have made a mistake, you could lock yourself out of a connection. ssh will not kill any existing sessions when reloading. Perform the next step before logging out of the terminal window.

Test your connection

Open another terminal window on the workstation you will be logging in from. Test you can make an ssh connect before exiting the session from the previous step.

If you can not make a connection, reverse your changes on the server using the other terminal window.

cp -av /etc/ssh/ /etc/ssh/sshd_config
/etc/init.d/ssh reload

Verify you can log in, then troubleshoot the issue.


You are now can now log in only via public key encryption, which denies many vectors of attack against your server. In order for someone to successfully connect to your server via ssh using your account, they must have your private key file and your encryption passphrase for it.

Limit the users who can log in via ssh

First, and most important, if you do not need root to have ssh access, turn it off. There are very few places where root should be allowed access to an ssh session. Ask yourself "can I do this by connecting as a non-privileged user, then elevate my privileges via sudo or su." If the answer is yes, turn off root ssh access.

Second, can you clearly define the logins which should have ssh access. Your Samba users do not need it, nor do your mail users. If you have a large number of users, but only a few of those should have ssh access, you can limit the users allowed access also.

Edit /etc/ssh/sshd_config again, and this time modify the following two lines to meet your needs.

PermitRootLogin no
AllowedUsers user1 user2 user3

Setting PermitRootLogin to "no" disables root logging in via ssh (the default on Debian systems is "yes"). Adding an AllowedUsers line (Debian no longer includes that) can limit users to a list of space separated patterns (in the above, the "patterns" are just names to match). You can also use AllowGroups. See man sshd_config if you need more information.

A note about PermitRootLogin. There are two additional values besides yes and no; "without-password" and "forced-commands-only". I can not see the need for without-password (I would simply set up a public key with no password myself), but forced-commands-only is very interesting. With this, you can prepend a script to your .ssh/authorized_keys files which is executed when a root ssh connection is made. Using this script, you can then limit the commands which can be executed and allow ssh to be a somewhat secure conduit for executing commands as root from a remote machine. I actually use this for some special purpose machines (see rsbackup in this wiki for a reason why).

Change the listening port from the default

Even though this is near the bottom of the list, it is the simplest way to secure your system under many circumstances.

By default, ssh listens on tcp port 22. Everyone knows this, and crackers will attempt to scan port 22, knowing it is reserved for ssh. If you have total control over the users accessing the system, changing one line in sshd_config can greatly increase your security.

Choose a port; any port. You have 65535 ports under Unix. Well some of them are reserved (like everything below 1024), but just randomly get an unused port.

If you are at a loss, the following one line perl script will create one for you.

perl -e '$port=0;while (($port=rand(65535)) <= 1024){} print int( $port ) . "\n";'

It could be optimized, but hey, it will be used one time.

Now, edit /etc/ssh/sshd_config again and find the line (near the top) which says "Port 22", changing that to the random number generated.

Port 36708

 Restart sshd (/etc/init.d/ssh reload) and your server will run on an unknown port. Crackers will most likely assume you have no ssh running and move on to someone else.

Your ssh logins from the remote machine must now use the -p option to define the correct port to look for. For example, to attach to "myserver" which has the above modification.

ssh -p 36708 me@myserver 


Use an intrusion detection system like fail2ban

 Actually, if you have changed the port number as per the previous, it is unlikely you will have repeated cracking attempts. However, there are several cases where this is just not possible, and fail2ban (and other IDS systems) can protect more than your ssh daemon. fail2ban is a standard Debian package, and the home page is located at

Install fail2ban with the following command under Debian

apt-get update && apt-get install fail2ban

fail2ban by default will protect port 22, I believe. If you are on a non-standard port, you should modify the port number in /etc/fail2ban/jail.conf (or preferably, create a new entry in jail.local).

fail2ban is too deep a subject for this article. Search for fail2ban in this wiki for more information (it has its own section)

Finally . . . .

There is one trick many people do not know about, appearantly, and that is a local configuration file which makes it easier to use ssh for multiple target systems.

Make entries in either ~/.ssh/config or /etc/ssh/ssh_config as follows

host     client.server
user     username_on_remote_machine
port     port_number

In the above, host is what you call it, and hostname is the real machine (either via IP address or DNS resolvable host name).. For example, you could have 

host client.server

 in your config file, and on the ssh call you would simply say ssh client.server.

user is the name for the user on the remote machine (if it is not entered, your current username is used). port is the port number to connect to (again, the default is 22 if this is not entered).

By creating one or more entries in .ssh/config, you can access systems without remembering which ports, what the username is, or where the machine actually is.

If you place the same information in /etc/ssh/ssh_config (appended to the file), this becomes a set of global resources for everyone on your system.

 Oh, by the way, there are tons more you can do with this. For example, host can be a pattern match, and hostname can include a special %h to match what was actually passed on the command line. So, typing ssh myhost could be ex[panded to ssh for lazy people like me. If you want the full power, RTFM (man ssh_config)

Tags: security
Last update:
2015-04-15 05:05
Average rating:0 (0 Votes)

You can comment this FAQ

Chuck Norris has counted to infinity. Twice.