Thwart automated attacks against your Internet-facing servers.
If you remotely administer a server across the Internet, you might notice large numbers of failed login attempts from time to time. These often have the telltale sign of coming from a single IP address for an account that is not meant for interactive logins but is commonly found on Unix systems.
For example:
Jun 24 22:15:52 oceana sshd[11632]: Failed password for www from 218.22.3.51 port 39766 ssh2 Jun 24 22:16:24 oceana sshd[11678]: Failed password for news from 218.22.3.51 port 40394 ssh2 Jun 24 22:16:33 oceana sshd[11687]: Failed password for games from 218.22.3.51 port 40563 ssh2 Jun 24 22:17:22 oceana sshd[11747]: Failed password for cvs from 218.22.3.51 port 41462 ssh2
Often, these are brute-force attacks coming from compromised computers in foreign countries, which usually makes contacting those responsible for the network block or domain and asking them to put a stop to the attacks an exercise in futility. Theoretically, you should be safe from them, as long as your users use adequately strong passwords and the attacks don’t persist for long enough to try a significant number of possible passwords. However, such attacks can make it more difficult to spot other attacks that might pose a more significant risk to your systems. Because of this, you’ll want to put a stop to them quickly.
Some methods for doing this are more effective than others. For instance, the most simple thing to do is to tell the SSH daemon to listen on a nonstandard port. For example, to have sshd listen on port 2200 instead of 22, you could put the following line in your sshd_config file (replacing the existing Port
entry):
Port 2200
This might stop an attacker who’s just looking for SSH daemons on their standard port, but it only requires a port scan to discover that you’re running the service on a nonstandard port. Also, this measure will cost your users the convenience of not having to specify the port to connect to when logging in via SSH. Nevertheless, it should significantly decrease the number of failed login attempts you see in your logs.
Another method is to disable password authentication. This will mean that users can only successfully connect when they have configured public-key authentication by generating a public/private key pair and copying the public key to ~/.ssh/authorized_keys on the server. Adding the following line to your sshd_config disables authentication via passwords:
PasswordAuthentication no
However, this will require that your users carry their private keys with them on portable media if they wish to be able to log in when traveling.
The next method is to firewall your SSH daemon. Here there are three approaches you can take.
The most restrictive approach is to allow connections to your sshd only from a specific list of IP addresses (i.e., a whitelist).
For instance, you could use something similar to the following PF rules:
table <ssh_allow> { 10.0.0.47, 10.0.0.98, 10.0.0.27 } block from any to any port 22 pass from <ssh_allow> to any port 22
However, this is obviously of limited use if your users need to be able to connect to their accounts when traveling.
The next approach is to parse your logs for failed login attempts and automatically block a given IP address once it has reached a threshold. If you go this route, make sure to whitelist any IP addresses that you connect from regularly, to avoid being inadvertently locked out if you mistype your password too many times.
The last approach is to rate-limit
SYN
packets going to the port on which your SSH daemon is listening. The effect of this should be unnoticed by legitimate users, but it will delay an attacker that is making many repeated connections because it allows only a certain number of undelayed connections. For instance, PF lets you specify a rate for any stateful rule. This one limits the connection rate to port 22 to three per minute:
pass inet proto tcp from any to any port 22 \ keep state (max-src-conn-rate 3 / 60)
This will most likely cause the attacker to give up, because of the inordinate amount of time that will be needed to successfully brute-force an account.