In this article, I will give some background on the SSH protocols as well as discuss some general, best-practice security settings. As with most things, everything I discuss must be evaluated with regard to your particular situation. In part 2, I will discuss some methods for reducing the number of brute force attacks against your ssh server.
Introduction
SSH is a client/server protocol that provides a secure communication channel between two computers by transparently (to the end user) encrypting the transferred data. It provides:
- Confidentiality: all data passing between the client and server is encrypted.
- Integrity: the SSH protocol detects if data is altered in transit, guaranteeing that transmitted data is unaltered by a third party.
- Authentication: the SSH protocol requires proof of identity to access the server. That proof can come in several forms (local or LDAP/Keberos password, public/private key pairs, etc) depending on the configuration.
SSH-1 was developed in 1995 by Tatu Ylönen as an ad-hoc solution for secure remote access. Interest in it grew and Ylönen released the source code. However, as a result of its ad-hoc nature, there were problems and limitations without workarounds. As a result, SSH-2, an incompatible new protocol based on SSH-1 was released in 1996. OpenSSH has become the dominant implementation of the SSH protocol and is available for many platforms, including BSD, Linux, and Solaris [1].
Since an SSH server is typically available over the internet, special attention must be paid to securing it from attack. The following instructions assume you are using OpenSSH, but should be applicable to other ssh implementations.
Security
Brute force attacks are a major security concern when running an ssh server. These automated attacks repeatedly attempt to login to ssh servers using common user names and passwords. These attacks became common in 2005 and continue today [2]. According to the SANS Top-20 Security Risks 2007:
Brute-force attacks against remote services such as SSH, FTP, and telnet are still the most common form of attack to compromise servers facing the Internet. Over the last couple of years a concerted effort has been made by attackers to recover passwords used by these applications via brute-force attacks. Increasingly worms and bots have brute-force password engines built into them. Systems with weak passwords for user accounts are actively and routinely compromised; often privilege escalations are used to gain further privileges, and rootkits installed to hide the compromise. It is important to remember that brute forcing passwords can be a used as a technique to compromise even a fully patched system.
If you are currently running an ssh server, check your access logs and you will likely see entries like:
May 20 14:46:24 xxx sshd[2700]: Invalid user user from ::ffff:xx.x.xx.xxx
May 20 14:46:24 xxx sshd[2700]: error: Could not get shadow information
for NOUSER
May 20 14:46:24 xxx sshd[2700]: Failed password for invalid user user from
::ffff:xx.x.xx.xxx port 41247 ssh2
There are many steps that an administrator can take to reduce both the number of these attacks and the likelihood that one will succeed. Here we will look at security measures that reduce the odds of a successful attack.
Strong Passwords Strong passwords typically contain:
- A mix of UPPER and lower case letters.
- Numbers.
- Special characters such as !@&
Additionally, passwords should not be too short, or based on dictionary words and personal information such as birthdate, and children's or pet's names. One effective password generation method is to select the first letter from a easily remembered phrase, substituting some special characters and numbers where appropriate. For example, Picasso's quote:
"Computers are useless. They can only give you answers"
could become caU.7c0gYA.
Public Key Authentication
Strong passwords are a good start, but rely on the user to choose a good
password. Even a mechanism to reject "bad" passwords can not guarantee that a
user will not choose something easily guessable, write it down on a sticky
note under their keyboard, or give it out via a social engineering attack.
Authentication can be done via a public/private key pair instead of an interactive password. Basically, you generate a pair of keys and place the public key on each server you want to log into. The private key must remain secure on every computer from which you will access the remote server. Authentication occurs as follows (note that the private key never leaves the client computer) [3]:
- The client and server contact each other and exchange a symmetric session key used for encrypting data during the session.
- The server issues a challenge that is encrypted with the user's public key.
The challenge message itself is encrypted with the session key. - The client decrypts the message with the session key and the challenge with the private key.
- The challenge is then encrypted with the session key and returned to the server where it is decrypted.
- If the challenge matches what the server sent, then the client must have the private key that matches the public key stored on the server for that user, thus, authenticating the user.
Below are details of how to generate the public/private key pair and configure the ssh server to use them for authentication. If you are doing this on a Debian or Debian-based system (Ubuntu, MEPIS, Xandros, etc) make sure you have an up to date version of OpenSSL due to a vulnerability in Debian's package. Any keys generated with a vulnerable OpenSSL should be revoked and regenerated.
Generate the key pair:
$ ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/home/user/.ssh/id_rsa):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/user/.ssh/id_rsa.
Your public key has been saved in /home/user/.ssh/id_rsa.pub.
The key fingerprint is:
XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX user@host
Note: It is strongly recommended that you enter a passphrase for your key. You can use ssh-agent and keychain to allow pseudo-passwordless ssh access.
Copy the public key to the server:
user@host:~$ scp ~/.ssh/id_rsa.pub user@remotehost:~/
Add the public key to the server's authorized_keys file:
$ ssh user@remotehost
user@remotehost's password:
$ cat id_rsa.pub >> ~/.ssh/authorized_keys
$ rm id_rsa.pub
Configure the server to use public key authentication
On the server, edit /etc/ssh/sshd_config ensuring that the following lines are present:
RSAAuthentication yes
PubkeyAuthentication yes
AuthorizedKeysFile .ssh/authorized_keys
Additionally, you may choose to disable password authentication by setting:
PasswordAuthentication no
Without this change, you allow both password and key based authentication.
Note: When changing the server configuration the service must be restarted to see the changes.
Secure Password-less Logins via ssh-agent and keychain
If you grow tired of entering your passphrase for every ssh connection, you
may run ssh-agent, which caches your passphrase for the session.
Unfortunately, ssh-agent alone will not allow ssh connections via cron jobs as
those run as a separate session. For that you need to configure keychain,
a bash script that allows the use of a single ssh-agent per system. While this
does open up a security hole - what if someone was able to get into your
account - use of the --clean option in a login script essentially treats
each login as a security breach until otherwise proven. It does so by clearing
the cache at login and requiring the passphrase again. This provides a
measure of security, while still allowing cron jobs access to the cache, since
the cache is cleared only at login.
Miscellaneous SSH Server Settings
Due to its insecure nature, unless you have good reason not to, you should
disable the SSH-1 protocol on the server. Additionally, you should not allow
root to log in. This removes a known username often used by brute force
attackers. You can simply su to root once logged in as a user. Make the
following changes in the /etc/ssh/sshd_config file:
Protocol 2
PermitRootLogin no
User Based Access Control You can limit ssh access to certain users on your system via the AllowUsers directive in /etc/ssh/sshd_config. For example:
AllowUsers pete
AllowUsers meg
would allow ssh connections only from pete and meg; no other accounts would be have access. You can also restrict access via DenyUsers.
Similarly, you can allow or deny access via groups. You could create a group sshusers and place all users that need ssh access into this group. You can then use the AllowGroups directive to specifically allow that group. There is an equivalent DenyGroups directive to deny access to particular groups.
Host Based Access Control
SSH access can be limited to hosts on a particular network or with a
particular IP address via /etc/hosts.allow. For example, to restrict access to
machines on your local network, you could place the following in
/etc/hosts.allow:
sshd:192.168.1.
This can also be done with iptables:
iptables -A INPUT -p tcp -s 192.168.1.0/24 --dport 22 -m state --state NEW
-j ACCEPT
The difference is that the iptables rule drops the connection at the firewall, attempt before it reaches the sshd daemon, while the daemon itself rejects the connection with the /etc/hosts.allow method.
References
[1] Barrett, D, Silverman, R, & Byrnes, R (2005). SSH, the Secure Shell. Sebastopol, CA: O'Reilly Media Inc.
[2] Wichmann, R (2008, 04 28). Samhain Labs. Defending against brute force ssh attacks Web site: http://www.la-samhna.de/library/brutessh.html
[3] (2008, 01 07). SSH, version 2. UVA Information Technology and Communication Web site: http://www.itc.virginia.edu/desktop/security/ssh.html#protection