Mitigating Brute Force Attacks
Put a server up on the internet (which allows SSH connections from anywhere and you'll quickly notice that there lots of machines which are constantly attempting to login to server via SSH via brute force attacks. So long as your users have strong passwords the risk isn't too high but it certainly is annoying.
Here is a very simple script which only allows a single IP address to SSH to your server 5 times each 60 seconds. Any IP address or subnet listed in TRUSTED_HOSTS will be able to connect as many times as it wants.
#!/bin/bash # Requires the ipt_recent kernel modules TRUSTED_HOSTS="127.0.0.1 192.168.4.192/26" iptables -A INPUT -p tcp --dport 22 -m state --state NEW -m recent --set --name SSH iptables -A INPUT -p tcp --dport 22 -m state --state NEW -j SSH_WHITELIST iptables -A INPUT -p tcp --dport 22 -m state --state NEW -m recent --update --seconds 60 --hitcount 5 --rttl --name SSH -j ULOG --ulog-prefix SSH_brute_force iptables -A INPUT -p tcp --dport 22 -m state --state NEW -m recent --update --seconds 60 --hitcount 5 --rttl --name SSH -j DROP for host in $TRUSTED_HOSTS; do iptables -A SSH_WHITELIST -s $host -m recent --remove --name SSH -j ACCEPT done
If you have legitimate reasons to connect more then 5 times within a 60 second timeframe you can either whitelist your IP address or using the connection sharing feature in modern versions of OpenSSH.
Versions of OpenSSH greater then 4.0 have a new feature which allows you to reuse a single SSH connection for all subsequent connections to that same host. This has two primary advantages
- Connections happen nearly instantaneously after the first one, this is because all subsequent connections use the first connections authentication and so don't have to perform their own.
- Since all your SSH connections appear as a single TCP session you can work around any restrictions on the destination network or host which limits the number of connections you are allowed (like in the above iptables script to mitigate SSH brute force attacks).
It's easy to implement, add these lines lines to your ~/.ssh/config, check the ssh man page for details:
Host * ControlMaster auto ControlPath ~/.ssh/sockets/%r@%h:%p
Update (8 Apr 08): I've been using this for a while now and the only downside I've found is that Subversion, using the svn+ssh protocol, doesn't clean up properly after itself and leaves a stale socket file behind when it closes the connection. There are two ways around this, make a normal ssh connection into the server before using Subversion (so Subversion is using the socket but isn't the master), or delete the socket and retry. The error looks like this:
overkill(shand)$ svn ci -m "" Control socket connect(/Usersemail@example.com:22): Connection refused