I want to decrease the likelihood of a successful ssh attack on a linux system. The only port that is open is 22 (I use port forwarding for everything else), and of course I made sure that ssh accepts only key-pair-based logins (no passwords).
The volume of failed ssh login attempts (output of last -f /var/log/btmp
) was fairly large (as anybody opening up port 22 should expect), so for the last 2+ years I've been relying on a variation af the iptables-based solutions often mentioned to block ssh attacks, for example Hundreds of failed ssh logins.
One annoying drawback of such a scheme is that it limits the number of new connections from an ip address per amount of time, no matter whether previous connections from that ip were successful or not and whether they were trying to log in as the same user or not. Imagine a script containing half a dozen of rsync
commands used from abroad to update various areas on that server: it typically hits the "new connection limit" and fails somewhere in the middle. The same goes if several users behind a router (showing up as the same IP address) do connect on my server more or less at the same time.
So, I am wondering if, without resorting to parsing the /var/log
files, it is possible to implement the following strategy with iptables
:
- accept established connections
- allow new connections from previously successful connections
- put IPs with failed connections in jail for some time
Bonus points:
- Same as above, but allowing/jailing specific
user@ip
instead of everybody@ip
.
And to attempt to curb botnet attacks:
- Temporarily put in jail a user (no matter which IP (s)he connects from) after a failed ssh attempt.
Without parsing logfiles, you can't know if an ssh login attempt was succesful. Fortunately you don't have to parse those logfiles yourself. fail2ban can do this for you. I generally jail an IP for a week after 3 failed login attempts.
2020 Update
Nowadays I just use
sshguard
(on containers) orfail2ban
withipset
(vm's / bare metal) - all with public keyssh
listening on a non standard port. I still limit access to this port withiptables
to my static ip's. Myfail2ban
config blocks attackers for 2 days withbantime = 48h
. I still use avpn
but am switching towireguard
.See also:
SSH Hardening to add 2 Factor Authentication
Onlykey SSH setup to put your
ssh
keys onto a Security Key. It also works withgpg
keys. It is much more secure than having your private keys on your pc. It is physically more secure than a Yubikey due to Onlykey being PIN protected.How to back up your 2FA secret keys with KeePassXC
Use a disposable Qubes vm for generating your keys
I also use Onlykey to secure KeepassXC as a
HMAC-SHA1
2nd Factor. It can also be used with Linux PAM to login to your system & be required forsudo
.With this setup I do not worry about
ssh
being exploited.First of all do not have
ssh
listen onport 22
to reduce the chance of your port being found by automated scanners.Also use
psad
to automatically block hosts which scan your machine for a configurable amount of time (1 hour by default).A very simple solution is to just rent a
64 or 128 meg
openvz
container & configureopenvpn
so you have afixed ip address
& then limit youriptables
rule to--source vpn.ip.address
on the host you wish to protect.A better solution is to completely stealth your
ssh
port withfwknop
. There is then no need to runfail2ban
as yourssh
port is closed until you send agpg
signed & encrypted packet from thefwknop-client
which will open your firewall for a configurable amount of time (30 seconds by default). You can also configurefwknop
to only accept certain ip addresses (such as yourvpn
).I have some quite extensive notes here for
fwknop
.If you are serious about
ssh
security you should also be usinged25519
keys. More notes here for using secure ciphers withopenssh
. Another a good choice istinyssh
which has no dependency onopenssl
& is secure by default.All of the software mentioned here exists in Alpine Linux which also benefits from address space layout randomization via
PaX
in it's Grsecurity kernel.