You are hereForums / Computers / CentOS server setup and maintenance notes / Securing Secure Shell
Securing Secure Shell
Under normal circumstances, I don't need to allow any remote access to my network. At most, I need to be able to check my e-mail and squirrelmail (see the squirrelmail article) now lets me do that. On the other hand, there are times when I'm gone for a long enough period that I really like to be able to log in from wherever and make sure everything is copacetic. Plus, there is always the possibility that the tape changer will throw a hissy fit and decide not to recognize one of the backup tapes or something similar will go wrong.
Since I typically don't need to allow any remote access, I usually have the firewall (iptables) configured to reject attempts to connect using secure shell (ssh). iptables is best configured with a blanket "disallow all" rule as the default and then having specific rules that open only specific ports required for services like e-mail, http, etc. My goal is to only open those ports that are required and have everything else blocked.
My first step in securing ssh really only cuts down on the noise from attempted forced break in attempts. I changed the listen port for my external interface to something other than port 22. sshd supports listening on different ports on different interfaces so I have the port for my external interface set to something non-standard while the internal interface is set to good old port 22. This way I don't have to do anything different to connect to my server from my internal network but I need to specify the port if I'm connecting to my server when I'm on the road. This looks like in /etc/sshd_config:
Port 22 Port 12345 Protocol 2 ListenAddress 72.19.169.230:12345 ListenAddress 192.168.255.254:22
I don't really use 12345 but someone who really wants to try to crack my system can do a port scan to find the actual port. Using a non-standard port just means that the script kiddies and bots won't find the port.
Given this approach, my standard iptables configuration looks like:
-A RH-Firewall-1-INPUT -p tcp -m tcp --dport 12345 --source ! 192.168.0.0/16 \
-j LOG --log-prefix "SSH port probed"
-A RH-Firewall-1-INPUT -m state --state NEW -m tcp -p tcp --dport 12345 -j DROPThe first rule tells iptables to log any attempt to probe, scan or log in through the ssh port. This lets me keep track of potential troublemakers. A future project for me is to write a script that digests the log file generated by this rule and create a "blacklist" of specific addresses that have attempted to connect in the past. The logged information looks like (this example is from when I still had ssh on port 22):
--------------------- iptables firewall Begin ------------------------ Logged 8 packets on interface eth0 From 61.152.223.194 - 2 packets to tcp(22) From 65.99.217.174 - 2 packets to tcp(22) From 76.68.243.28 - 1 packet to tcp(22) From 200.30.187.18 - 1 packet to tcp(22) From 216.185.75.36 - 1 packet to tcp(22) From 218.106.51.107 - 1 packet to tcp(22) ---------------------- iptables firewall End -------------------------
The second rule explicitly drops any packets to the ssh port. It really isn't needed since the default rule:
-A RH-Firewall-1-INPUT -j REJECT --reject-with icmp-host-prohibited
at the bottom of the rule list throws out anything that doesn't match an allow rule.
This was all I used for quite sometime along with an allow rule that looked a lot like the explicit drop rule except it has the word "ACCEPT" as the disposition. The downside of this method to allowing access is it opened my system to a brute force, guessing attack and the attempts to do this left a mess of failed login messages in my log files.
I ran across a better way on the CentOS mailing list. I added two more rules below the "ssh disallow rule" above:
# Block brute force attacks
# Drop repeated ssh connection attempts within 20 seconds interval
-A RH-Firewall-1-INPUT -p tcp -m tcp -m state -m recent -i eth0 --dport 12345 \
--state NEW -j DROP --rcheck --seconds 20 \
--name THROTTLE --rsource
# Accept ssh connection if not attempted within past 20 sec.
-A RH-Firewall-1-INPUT -p tcp -m tcp -m state -m recent -i eth0 --dport 12345 \
--state NEW -j ACCEPT --set --name THROTTLE --rsourceThe key to understanding these to rules is to realize that the first rule has no effect on a new connection attempt. The second rule fires on a new connection attempt (the "--state NEW" qualifier). It also sets the remote source address (--rsource) into an internal list called THROTTLE. If the login is successful, everything is fine, the connection is made and the first rule never fires.
If, on the other hand, either the remote user botches the password or this is a brute force hacking attempt, the next login attempt hits the first rule. This rule looks for "recent" connection attempts and disallows them if they came from the same address within the last twenty seconds (the twenty seconds seemed like a reasonable time penalty). The chances of a dictionary password attack succeeding in less than the age of the universe given this kind of time penalty is very small.
Another way of cutting down on the noise of failed login attempts is to further restrict who can connect using ssh through PAM. This is done by creating a group for the users who can use ssh to login and then including a PAM directive that says allow only users in that group to ssh in. This is done by adding something like:
AllowGroups ssh_users
to /etc/sshd_config and then adding only the users who are allowed to remotely connect to the ssh_users group. Note that unlike the standard configuration items in sshd_conf this directive must be added explicitly.
Finally, I only allow public key access to my server. This is done by configuring sshd with:
PasswordAuthentication no ChallengeResponseAuthentication no PubkeyAuthentication yes
which disallows simple password authentication and challenge response authentication. Public key authentication is on by default in the CentOS ssh installation but I show it here for completeness.
There are several ssh public key authentication how-tos on the Internet. I include the steps here for completeness:
- On the system that is to be allowed access (also called the client or local system), generate RSA keys using ssh_keygen. This looks like:
- Add the public key file that is created (~/.ssh/id_rsa.pub) to the system that is to be accessed (the server or remote system) and append it to the ~/.ssh/authorized_keys file.
ssh-keygen -q -f ~/.ssh/id_rsa -t rsa
Given this setup, the throttle rules above just cut down on the failed login attempts when I have the ssh port open.
Cheers,
Dave
- Login to post comments
![DaveAtFraud on Technorati [Technorati Profile]](http://davenjudy.org/me.jpg)

![Validate my RSS feed [Valid RSS]](http://davenjudy.org/valid-rss.png)