The Ultimate SSH Security Tutorial

openbsd.png

SSH is one of the most secure communication methods we have. It’s encrypted, and even the passwords can’t be sniffed. But it’s not invincible. Weak passwords can be brute forced and open ports invite automated bots looking for that open port 22. But there’s a number of ways we can harden our ssh server.

Note: Ubuntu, Mint, Linspire, and Debian Readers, please read this regarding an OpenSSL Vulnerability:

Windows to Linux SSH Keys

This tutorial walks through how to setup RSA keys for stronger security logging into your linux/unix box via ssh when you’re on a windows system using Putty.

Please See: http://www.howtoforge.com/ssh_key_based_logins_putty

Linux to Linux SSH Keys

SSH is either installed by default, or you can install it on your distribution from their repositories.

In Suse, it is on the DVD/CD. Make sure that’s in your drive and in turned on in your sources then zypper in ssh. In Ubuntu, to install ssh server do an apt-get install ssh.

Requirements

First, before starting, the following assumptions are made:

  • You have enabled sshd on the remote server.
  • You have opened the appropriate port for sshd on the remote server.
  • You are careful enough to know that you should not set up public key authentication for the root user.
  • You are capable of choosing between RSA or DSA keys. (In this example I have chosen RSA.)
  • Note: This is written for SuSE 9.2; other versions should be similar or identical.

Preparing the client

1. If it does not exist, create the ~/.ssh directory for your user.
2. Generate the public / private key pair with the command

$ ssh-keygen -t rsa -b 2048 -f ~/.ssh/id_rsa

Note: When prompted for a passphrase, just hit enter, and then enter again. See the man pages for ssh-keygen for various options, if you’d like to try something different. This will generate a private and a public (.pub) key file.

Remember – If you choose not to use a password for your private key, anyone who gets access to it automatically gets access to any server you have access to. They will not need a password, they will just need to use that key (leave your computer for 2 minutes, loose your laptop, someone gets access another way etc). Easy. If you need to have no passwords (for cron etc), make sure the user is very limited, consider using a jail, or use ssh-agent.
3. As root, edit the /etc/ssh/ssh_config file in the following ways:

  • Remove the comment (#) from the line

IdentityFile ~/.ssh/id_rsa

  • Remove the comment (#) from the line

Protocol 2

(and while you are at it, if there is a 1 there, remove it; there should only be a 2 unless you have some strange reason to use protocol 1)

Preparing the server

  1. Log in to the remote server using the normal ssh password authentication.
  2. Make sure the ~/.ssh directory exists.
  3. Make sure permissions on the ~/.ssh directory are 700.
  4. Now from the client machine copy the .pub key you generated to ~/.ssh on the server. You can do this with something like (from the client machine):

$ scp ~/.ssh/id_rsa.pub user_name_here@server_here:~/.ssh

That will prompt you for a password to complete.
5. Now ssh to the server again, and run the following command:

$ cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys

6. Next, as root, edit the /etc/ssh/sshd_config file in the following ways:

  • If the line

Protocol 2

has a 1 as well, remove it unless you have some strange reason to use protocol 1. Also remove comment (#) if it is there.

  • Edit the line

PubkeyAuthentication yes

(i.e. if it says no, change it to yes) Also remove comment (#) if it is there.

  • If you want to disable password-login, make sure the file includes a line like

PasswordAuthentication no

  • If you want to disable password-login for root:

PermitRootLogin without-password

  • Make sure the line

AuthorizedKeysFile .ssh/authorized_keys

is set up correctly (i.e. if it is pointing to a different keys file, then update to what is shown here). Also remove comment (#) if it is there.

  • Check if you need to disable PAM authentication! Comments in sshd_config state: Depending on your PAM configuration, this may bypass the setting of PasswordAuthentication, PermitEmptyPasswords, and “PermitRootLogin without-password”

ChallengeResponseAuthentication no
UsePAM no

7. As root, restart sshd:

# rcsshd restart
(or on Ubuntu/Debian: sudo /etc/init.d/ssh restart )

That’s it. Now try logging in from your client machine – you should be logged in automatically without being prompted for a password.

Prevent Brute Force Attacks with Fail2Ban

In this article I will show how to install and configure fail2ban on your system. Fail2ban is a tool that observes login attempts to various services, e.g. SSH, FTP, SMTP, Apache, etc., and if it finds failed login attempts again and again from the same IP address or host, fail2ban stops further login attempts from that IP address/host by blocking it with an iptables firewall rule.

Fail2ban is similar to DenyHosts but unlike DenyHosts which focuses on SSH, fail2ban can be configured to monitor any service that writes login attempts to a log file, and instead of using /etc/hosts.deny only to block IP addresses/hosts, fail2ban can use iptables and /etc/hosts.deny.

In this example I will configure fail2ban to monitor login attempts to the SSH server, the Proftpd server, login attempts to .htaccess/.htpasswd protected web sites, to Courier POP3 and Courier IMAP, and to SASL (for sending emails). I will install the fail2ban package. It comes with a default configuration, but unfortunately that configuration doesn’t quite work for most of the aforementioned services. Therefore I will create a customized fail2ban configuration that I have tested and that works for me.

Install

In Suse: yast2 -i fail2ban

In Ubuntu: sudo apt-get install fail2ban

In Fedora: yum install fail2ban

Then we must create the system startup links for fail2ban and start it:

chkconfig –add fail2ban
/etc/init.d/fail2ban start

You will find all fail2ban configuration files in the /etc/fail2ban directory.

Configuring fail2ban

The default behaviour of fail2ban is configured in the file /etc/fail2ban/jail.conf. Take a look at it, it’s not hard to understand. There’s a [DEFAULT] section that applies to all other sections unless the default options are overriden in the other sections.

I explain some of the configuration options here:

  • ignoreip: This is a space-separated list of IP addresses that cannot be blocked by fail2ban. For example, if the computer from which you’re connecting to the server has a static IP address, you might want to list it here.
  • bantime: Time in seconds that a host is blocked if it was caught by fail2ban (600 seconds = 10 minutes).
  • maxretry: Max. number of failed login attempts before a host is blocked by fail2ban.
  • filter: Refers to the appropriate filter file in /etc/fail2ban/filter.d.
  • action: Refers to the appropriate action file in /etc/fail2ban/action.d.
  • logpath: The log file that fail2ban checks for failed login attempts.

This is what my /etc/fail2ban/jail.conf file looks like:

vi /etc/fail2ban/jail.conf


# Fail2Ban configuration file
#
# Author: Cyril Jaquier
#
# $Revision: 611 $
#
# The DEFAULT allows a global definition of the options. They can be override
# in each jail afterwards.
#
[DEFAULT]
#
# "ignoreip" can be an IP address, a CIDR mask or a DNS host. Fail2ban will not
# ban a host which matches an address in this list. Several addresses can be
# defined using space separator.
ignoreip = 127.0.0.1 192.168.0.99
#
# "bantime" is the number of seconds that a host is banned.
bantime = 600
#
# A host is banned if it has generated "maxretry" during the last "findtime"
# seconds.
findtime = 600
#
# "maxretry" is the number of failures before a host get banned.
maxretry = 3
#
# "backend" specifies the backend used to get files modification. Available
# options are "gamin", "polling" and "auto". This option can be overridden in
# each jail too (use "gamin" for a jail and "polling" for another).
#
# gamin: requires Gamin (a file alteration monitor) to be installed. If Gamin
# is not installed, Fail2ban will use polling.
# polling: uses a polling algorithm which does not require external libraries.
# auto: will choose Gamin if available and polling otherwise.
backend = auto
#
# This jail corresponds to the standard configuration in Fail2ban 0.6.
# The mail-whois action send a notification e-mail with a whois request
# in the body.
#
[ssh-iptables]
#
enabled = true
filter = sshd
action = iptables[name=SSH, port=ssh, protocol=tcp]
sendmail-whois[name=SSH, dest=you@mail.com, sender=fail2ban@mail.com]
logpath = /var/log/messages
maxretry = 5
#
[proftpd-iptables]
#
enabled = true
filter = proftpd
action = iptables[name=ProFTPD, port=ftp, protocol=tcp]
sendmail-whois[name=ProFTPD, dest=you@mail.com]
logpath = /var/log/messages
maxretry = 6
#
# This jail forces the backend to "polling".
#
[sasl-iptables]
#
enabled = true
filter = sasl
backend = polling
action = iptables[name=sasl, port=smtp, protocol=tcp]
sendmail-whois[name=sasl, dest=you@mail.com]
logpath = /var/log/mail
#
# Here we use TCP-Wrappers instead of Netfilter/Iptables. "ignoreregex" is
# used to avoid banning the user "myuser".
#
[ssh-tcpwrapper]
#
enabled = false
filter = sshd
action = hostsdeny
sendmail-whois[name=SSH, dest=you@mail.com]
ignoreregex = for myuser from
logpath = /var/log/messages
#
# This jail demonstrates the use of wildcards in "logpath".
# Moreover, it is possible to give other files on a new line.
#
[apache-tcpwrapper]
#
enabled = true
filter = apache-auth
action = hostsdeny
logpath = /var/log/apache2/error_log
maxretry = 6
#
# The hosts.deny path can be defined with the "file" argument if it is
# not in /etc.
#
[postfix-tcpwrapper]
#
enabled = true
filter = postfix
action = hostsdeny
sendmail[name=Postfix, dest=you@mail.com]
logpath = /var/log/mail
bantime = 300
#
# Do not ban anybody. Just report information about the remote host.
# A notification is sent at most every 600 seconds (bantime).
#
[vsftpd-notification]
#
enabled = false
filter = vsftpd
action = sendmail-whois[name=VSFTPD, dest=you@mail.com]
logpath = /var/log/messages
maxretry = 5
bantime = 1800
#
# Same as above but with banning the IP address.
#
[vsftpd-iptables]
#
enabled = false
filter = vsftpd
action = iptables[name=VSFTPD, port=ftp, protocol=tcp]
sendmail-whois[name=VSFTPD, dest=you@mail.com]
logpath = /var/log/messages
maxretry = 5
bantime = 1800
#
# Ban hosts which agent identifies spammer robots crawling the web
# for email addresses. The mail outputs are buffered.
#
[apache-badbots]
#
enabled = true
filter = apache-badbots
action = iptables-multiport[name=BadBots, port="http,https"]
sendmail-buffered[name=BadBots, lines=5, dest=you@mail.com]
logpath = /var/log/apache2/access_log
bantime = 172800
maxretry = 1
#
[courierpop3]
#
enabled = true
port = pop3
filter = courierlogin
action = iptables[name=%(__name__)s, port=%(port)s]
logpath = /var/log/mail
maxretry = 5
#
[courierimap]
#
enabled = true
port = imap2
filter = courierlogin
action = iptables[name=%(__name__)s, port=%(port)s]
logpath = /var/log/mail
maxretry = 5

My client computer has the static IP address 192.168.0.99, and because I don’t want to be locked out, I’ve added it to the ignoreip list.

I want to control login attempts to SSH, Apache, Proftpd, Courier-POP3, Courier-IMAP, and Sasl, so I’ve set enabled to true for these services and to false for all other services. Please note that some services such as SSH can be blocked either by iptables or by TCPWrappers (/etc/hosts.deny). Decide for yourself which method you prefer.

Make sure to replace the email address you@mail.com with your own email address so that you get notified when someone gets blocked by fail2ban.

If you compare the file with the default /etc/fail2ban/jail.conf, you’ll also notice that I’ve changed some log files because the log files in the default /etc/fail2ban/jail.conf are not correct for OpenSUSE 10.3. If you are not using Opensuse, make sure they are correct.

Whenever we modify the fail2ban configuration, we must restart fail2ban, so this is what we do now:

/etc/init.d/fail2ban restart

That’s it already. Fail2ban logs to /var/log/fail2ban.log, so you can check that file to find out if/what hosts got blocked. If a host got blocked by fail2ban, it looks like this:

2007-10-07 17:49:09,466 fail2ban.actions: WARNING [apache-tcpwrapper] Ban 1.2.3.4
2007-10-07 18:08:33,213 fail2ban.actions: WARNING [sasl-iptables] Ban 1.2.3.4
2007-10-07 18:26:37,769 fail2ban.actions: WARNING [courierlogin] Ban 1.2.3.4
2007-10-07 18:39:06,765 fail2ban.actions: WARNING [courierimap] Ban 1.2.3.4

You can also check your firewall to see if any hosts are currently blocked. Simply run

iptables -L

For services that use TCPWrappers to block hosts, take a look at /etc/hosts.deny.

Properly Configure /etc/hosts.allow

The hosts.allow file is checked before hosts.deny, so make sure the rules don’t conflict.

  1. su (type root password)
  2. cd /etc/
  3. vi hosts.allow (you can substitute vi with any text editor of your choice. ex: kate, gedit, mousepad, nano ) Use sudo for this command if you are using Debian or Ubuntu.

Allowing things should be in the allow-file, like:

ALL : 127.0.0.1
sshd: xxx.xxx.xxx.xxx, xxx.xxx.xxx.xxx, xxx.xxx.xxx.xxx

So enter the above lines into your hosts.allow file. the xxx ip address should be the ip(s) that you are connecting from that should be allowed.

Properly Configure /etc/hosts.deny

  1. vi hosts.deny ( hosts.deny lists the hosts that are not allowed to access the system)
  2. place this line in your hosts.deny file:

ALL : ALL
sshd: xxx.xxx.xxx.xxx
sshd: xxx.xxx.xxx.xxx

Configure /etc/ssh/sshd_config

  1. vi ssh_config
  2. Make sure the following linses are uncommented and have the appropriate values
    • RSAAuthentication yes
    • Port 6545 (i made up this port, you should use a non-standard port as well)
    • Protocol 2 (make sure it does not specify a “1″)
    • PasswordAuthentication no (do this ONLY if you have set up keys shown above)
    • AllowUsers user_name1, user_name2 (specify which user names are allowed to access the system)
    • PermitRootLogin no

Now restart sshd

/etc/init.d/sshd restart

Configure /etc/ssh/ssh_config

This file controls who from this box can ssh out. If you have other boxes in your internal network with ssh open, but not exposed to the outside world, it would be best to set a few options on this as well.

  • Protocol 2 (make sure it does not specify a “1″)
  • AllowUsers user_name1, user_name2 (specify which user names are allowed to ssh out)

Setup Tight Firewall Rules

  1. Know the IPs you will be connecting from. Only allow these IPs on the SSH port you have chosen (default 22). Blacklist everything else.
  2. Only Allow Outgoing traffic on ports you know you will be using. Blacklist all else.

Common Practices:

  1. Make your keyphrase difficult if you set one for the RSA keys
  2. Do not lose your keys. Make a backup (and encrypt that backup) if you have to.
  3. Use a non-standard port on your router and forward that to your ssh box.

If you love openssh, please support this project. The OpenBSD project is always in need of extra funding:

Related Posts

Comments are closed.