Securing your ssh server
rackerhacker.com
rackerhacker.com
For anyone curious I put my modified iptables rules up at http://pastebin.com/UPL3w6FQ
Backstory:
I wrote a quick django app that watches fail2ban logs and plots a heatmap of where in the world the attacks are coming from. After watching this for a bit I found that most of these attacks originate from Chinese and Korean IP space. So I set out to block all of China and Korea.
After some googling, I found that okean.com maintains a handy SMTP Chinese/Korean iptables ruleset at http://www.okean.com/antispam/iptables/rc.firewall.sinokorea. I took their rules and modified it to drop all traffic from these IPs instead of just port 25.
FWIW though I have almost no traffic to these boxes, so I've never noticed any sort of performance issues.
The author of the article advocates filtering to trusted sources because it's so much more effective. Ask yourself just how often you access your sshd from a new-to-you location. I'd be willing to bet that it isn't so often that you can't anticipate it. This effectively becomes a third factor in your authentication schema. It requires any attacker to have your private key, know it's passkey, and be at a pre-approved location. Gaining access to your sshd then necessitates attack vectors for your sshd, your private key or the encryption algorithm you used to generate it, and netfilter or whatever runs your firewall.
When I had sshd running on the standard port on my MacMini, it would often slow down and start spinning the fan like crazy while some cracker was bruteforcing accounts and passwords. Now that I have it on a non-standard port, that never seems to happen anymore.
Running sshd on a nonstandard port isn't in itself a bad idea (other than the potential difficulty of logging into the server later if you forget the port or something), but it shouldn't be considered a strong security measure at all.
I used to change ssh's port, but not anymore. If a bruteforce attack is a threat to you, then you are better being compromised by a random script kiddie or spammer than by a targeted attacker looking after your data. Take that scans as free, low skilled, penetration tests.
Host example.com
Port #####
to your ~/.ssh/configBesides it is more like a one time annoyance unless you are one of those crazy people that formats without backups every month.
When a user connects to these phony ports, their IP is blocked, or at least blocked from the ports which run legitimate services.
Are there any similar programs, or perhaps some flaw with this idea that I'm not seeing?
About automatic blocking: Be careful to not block legit users or services after a flood of spoofed packets to your $device.
http://www.digitalsanctuary.com/tech-blog/debian/using-iptab...
Although now I've moved to CSF which does this and much much more.
-A SSH_CHECK -m recent --set --name SSH --rsource
-A SSH_CHECK -m recent --update --seconds 60 --hitcount 4 --name SSH --rsource -j REJECT --reject-with icmp-port-unreachable
-A SSH_CHECK -p tcp -m tcp --dport 22 -j ACCEPT
This is in addition to default REJECT for everything that I don't explicitly allow.(Incidentally, the kernel I'm running doesn't support this for ipv6 addresses... so you can bruteforce my ssh server over ipv6 for as long as you want. But fortunately, it's hard to automatically scan the entire ipv6 address space :)
http://blog.andrew.net.au/2005/02/16#ipt_recent_and_ssh_atta...
I know it's pretty tin foil hat of me but another layer is always good.
*open source.
I tried using denyhosts (also mentioned in the article), but OSX 10.6 is ignoring /etc/hosts.deny, and it doesn't come with iptables. I do not want to disable passwords (i.e. use key-only authentication), since I tend to ssh to my home machine from various computers. And I can't change the port number due to firewall issues at my office.
Any other ideas?
http://en.wikipedia.org/wiki/Ipfirewall
http://en.roolz.org/Blog/Entries/2009/11/6_OpenBSD_PF_on_Mac...
Basically they offload your private keys to a dedicated device, completely in hardware, that's isolated from the machine's memory, so they can't be compromised via a software attack. The only attacks I've ever seen used to retrieve the primary key involve cracking the case and trying to open the chips up physically.
The cards are OpenPGP, and have room for three keys, up to 3072 bit RSA. The first two are pretty standard PGP keys, a signing key and and encryption key.
The third doesn't get used as much. It's a 'certification' key. If you have a certification key, you can use gpg-agent as a drop-in replacement for ssh-agent. And then you don't need an id_rsa file or anything like that stored on your computer. It's all on the card.
When you ssh into a box that has your public key setup, gpg-agent asks for your passphrase. Once that's done, the session key and that stuff gets setup on the smartcard. Since all that happens on the card, it doesn't matter if your system is compromised, the key can't be retrieved. (It also invalidates that old XKCD joke about getting your password with a rubber hose. If you destroy the device, your password is useless.)
The cards also lock out after three invalid passwords, so they can't be brute forced. If you do lock it out, there's an admin password to remove the lock. If someone gets that wrong three times, it actually erases the keys and turns the device into a brick.
It's really way more secure than I need, but it's a neat little gadget.
Anyway, I've seen dozens of articles over the years talking about securing a server's ssh config. But I've never seen one that addressed securing the clients...
Sounds like a good blog post on how you set things up if you do maintain a blog somewhere. =D
The only place I know of that gets this right is Amazon, who stands it up with a key (admittedly one of theirs) that they force you to download before you can connect the first time.
Right now my big problem is that the channel for the public key is email, which is no good.
On larger deployments I've always put the ssh pubkeys for authorized users in a package that is installed when the server is installed.
Comments and critiques regarding the following script are most welcome.
#!/bin/bash
# Rules:
# http://www.newartisans.com/2007/09/neat-tricks-with-iptables.html
# Sel also:
# https://help.ubuntu.com/community/IptablesHowTo
echo "[SCRIPT] Limit to ports 1222 and 80."
iptables -F
iptables -P INPUT ACCEPT
iptables -P OUTPUT ACCEPT
iptables -P FORWARD ACCEPT
iptables -A INPUT -i lo -j ACCEPT
iptables -A INPUT -p icmp --icmp-type any -j ACCEPT
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -A INPUT -m state --state NEW -m tcp -p tcp --dport 1222 -j ACCEPT
iptables -A INPUT -m state --state NEW -m tcp -p tcp --dport www -j ACCEPT
iptables -A INPUT -j REJECT --reject-with icmp-host-prohibited
iptables -A FORWARD -j REJECT --reject-with icmp-host-prohibited
echo "[SCRIPT] Ban incorrect SSH login attempts (120 seconds)."
iptables -A INPUT -i lo -p all -j ACCEPT
iptables -A OUTPUT -o lo -p all -j ACCEPT
iptables -A INPUT -i eth1 -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -A INPUT -p tcp ! --tcp-option 2 -j REJECT --reject-with tcp-reset
iptables -I INPUT -p tcp --dport 1222 -i eth0 -m state --state NEW \
-m recent --set
iptables -I INPUT -p tcp --dport 1222 -i eth0 -m state --state NEW \
-m recent --update --seconds 120 --hitcount 4 -j DROP
iptables -P INPUT DROP
echo "[SCRIPT] Drop spoofed IP addresses."
iptables -A INPUT -s 10.0.0.0/8 -j DROP
iptables -A INPUT -s 169.254.0.0/16 -j DROP
iptables -A INPUT -s 172.16.0.0/12 -j DROP
iptables -A INPUT -s 224.0.0.0/4 -j DROP
iptables -A INPUT -d 224.0.0.0/4 -j DROP
iptables -A INPUT -s 240.0.0.0/5 -j DROP
iptables -A INPUT -d 240.0.0.0/5 -j DROP
iptables -A INPUT -s 0.0.0.0/8 -j DROP
iptables -A INPUT -d 0.0.0.0/8 -j DROP
iptables -A INPUT -d 239.255.255.0/24 -j DROP
iptables -A INPUT -d 255.255.255.255 -j DROP
echo "[SCRIPT] Limit spamming PINGs."
iptables -A INPUT -p icmp -m icmp --icmp-type address-mask-request -j DROP
iptables -A INPUT -p icmp -m icmp --icmp-type timestamp-request -j DROP
iptables -A INPUT -p icmp -m icmp -m limit --limit 2/second -j ACCEPT
echo "[SCRIPT] Drop packets with an invalid state."
iptables -A INPUT -m state --state INVALID -j DROP
iptables -A FORWARD -m state --state INVALID -j DROP
iptables -A OUTPUT -m state --state INVALID -j DROP
echo "[SCRIPT] Drop SYN,FIN invalid ordering."
iptables -A INPUT -p tcp -m tcp --tcp-flags SYN,FIN SYN,FIN -j DROP
iptables -A INPUT -p tcp -m tcp --tcp-flags SYN,RST SYN,RST -j DROP
echo "[SCRIPT] Limit RST RST spam."
iptables -A INPUT -p tcp -m tcp --tcp-flags RST RST \
-m limit --limit 2/second --limit-burst 2 -j ACCEPT
echo "[SCRIPT] Restrict port scanners for 24 hours."
iptables -A INPUT -m recent --name portscan --rcheck --seconds 86400 -j DROP
iptables -A FORWARD -m recent --name portscan --rcheck --seconds 86400 -j DROP
iptables -A INPUT -m recent --name portscan --remove
iptables -A FORWARD -m recent --name portscan --remove
echo "[SCRIPT] Drop scans on port 139 (Microsoft)."
iptables -A INPUT -p tcp -m tcp --dport 139 \
-m recent --name portscan --set -j LOG --log-prefix "Portscan:"
iptables -A INPUT -p tcp -m tcp --dport 139 \
-m recent --name portscan --set -j DROP
iptables -A FORWARD -p tcp -m tcp --dport 139 \
-m recent --name portscan --set -j LOG --log-prefix "Portscan:"
iptables -A FORWARD -p tcp -m tcp --dport 139 \
-m recent --name portscan --set -j DROP
iptables-save > /etc/network/iptables
printf '#!/bin/sh\niptables-restore < /etc/network/iptables\n' > /etc/network/if-pre-up.d/iptables
chmod 754 /etc/network/if-pre-up.d/iptables