37 comments

[ 3.3 ms ] story [ 80.1 ms ] thread
What's the problem with brute-force attacks? Why can't a simple incorrect-password timeout prevent them?
If the encrypted private-key is stolen, then it can be stored on a powerful computer and brute-force attacks can be applied on it. Even if symmetric encryption is used to encrypt the private-key ( which makes straight-on brute-force attacks unfeasible), if the user uses an easy passphrase to encrypt the private-key, then the private-key can be compromised.

From Wikipedia:

In the case of an offline attack where the attacker has access to the encrypted material, he can try key combinations at his leisure without the risk of discovery or interference. However database and directory administrators can take countermeasures against online attacks, for example by limiting the number of attempts that a password can be tried, by introducing time delays between successive attempts and locking accounts out after unsuccessful logon attempts. Website administrators may prevent a particular IP address from trying more than a predetermined number of password attempts against any account on the site.

That would be ok against the brute force attacks which involve one account and lots of passwords. It doesn't work so well against brute force attacks which involve just a few passwords and lots of accounts on lots of servers.
There doesn't appear to be a way to prevent these attacks without locking out legitimate users, making DoS (denial-of-service attacks) trivial (thereby locking out legitimate users), or both. The fundamental problem is that the bad guys can open lots of connections.

Suppose you pause for 10s (after an incorrect password/before checking the password/...). This make it very easy to spawn so many sshd processes that you end up with a DoS (either the system stops spawning sshd processes, locking out everyone, or it is overwhelmed). If you solve this somehow, the bad guys can just open a ton of connections and just wait 10s - they'll need more connections, but they can still saturate the link with login attempts. Blocking IPs after too many connections doesn't help much against botnets; limiting the number of total connections locks out legitimate users; blocking all but specific address blocks locks out legitimate users (at home, or your sysadmin-on-a-holiday trying to fix your system in an internet cafe halfway across the globe.)

In short, anything you do seems to make it easy (easier) to lock out legitimate users. On the other hand, switching to private-key-only or private-key-and-one-time-password-only (or instituting a check on password quality) makes this attack infeasible.

Why doesn't opening a large number of connections to a server secured by private-key work as a DoS attack? Isn't the number of connections required to overload the system the same regardless of security method?
The number of connections is equal, but it is - at least in theory - possible to set a lower timeout when using private keys.
We solved a lot of our "battering ram at the gate" problems by simply moving our SSH port. It seems that most hackers go after low hanging fruit. I'd venture they're looking for people who aren't paying attention to security. The number of ssh auth attempts against our VPSs dropped by at least one order of magnitude when we moved the sshd off the default port. Prior to the move, the fail2ban process ranked third or fourth for CPU time on most of our VPSs behind processes like MySQL or our app server. Now that we've moved ports, it's at 10th or 15th. We're going to implement a port knocking setup as well. That should limit our exposure to targeted attacks.
(comment deleted)
There doesn't appear to be a way to prevent these attacks without locking out legitimate users

There is, but I've never seen it implemented. Throttle login attempts by requiring a cryptographic proof-of-work to accompany each attempt. Send the credentials and proof-of-work over UDP so that there's no connection state to hold open. Scale the required amount of work up and down based on the total number of incorrect attempts in the past minute. After a successful login, issue systems a long-lived cookie that exempts them from future proof-of-work requirements. That way, during attacks, legitimate users may experience a longer delay when trying to log in, but only if they've never logged in from that system before, and they can never be locked out completely.

Proof-of-work systems are really neat, but that's cheating: if you make it optional, it doesn't work at all, and if you make it mandatory, you're arguably not speaking SSH anymore.

Besides, I, too, do not recall any actually working implementations.

I meant this as a general answer to the brute-force-mitigation-without-DoS-vulnerability problem, not as something SSH-specific. Somewhere on my hard drive I have a half-finished draft of a spec for a Kerberos replacement implementing the idea.
I've nearly eliminated the problem with brute force attacks, but it's quite multilayered. I use public key authentication with strong passphrases, but leave password authentication enabled for the standard port, so I'll focus on that as the weak link. Assuming high quality passwords and nonobvious user names on systems where password authentication is allowed, set "PermitRootLogin no", "MaxAuthTries 3", and explicitly list users: "AllowUsers fooz1 barx2 cary3" in sshd_config. This is usually enough to foil most random brute force attacks seeking low hanging fruit. After that, the main problem is log noise and the fact that the attack has been slowed, but not stopped. My next line of defense is a short-lived block using the recent module in my iptables startup script (on Linux):

  IPTABLES=/usr/sbin/iptables
  # only allow up to 2 connections in a 15 second period
  $IPTABLES -A INPUT -p tcp --dport 22 \
        -m state --state NEW \
        -m recent --update --seconds 15 --hitcount 2 \
        -j DROP
  $IPTABLES -A INPUT -p tcp --dport 22 \
        -m state --state NEW \
        -m recent --set \
        -j ACCEPT
That's enough to really slow down brute force attacks without locking out fat-fingered users for too long.

Finally, I use fail2ban to block persistent attacks for 6 hours after 8 failures/hr in jail.conf:

  # Failed login attempts against SSH (port 22)
  [ssh-iptables]
  enabled  = true
  filter   = sshd
  logpath  = /var/log/messages
  maxretry = 8
  bantime  = 21600
  findtime  = 3600
  action   = iptables[name=SSH, port=ssh, protocol=tcp]
           sendmail-whois-lines[name=SSH, dest=admin, logpath=/var/log/messages]
This allows me to identify attacks and penalize them hard without affecting real users. This basically leaves a DoS as the only threat, and only if you're using the same IP address as the attacker.

It may look complicated, but it only takes a few minutes to set up and doesn't require using a nonstandard port (which you can do to further harden the system, along with other things). In my experience, this has been enough to thwart brute force attacks against ssh.

Even better: two factor authentication.

http://en.wikipedia.org/wiki/Two-factor_authentication

Are there any examples of people using these to access a sshd? I know it's becoming common practice for access to VPN, etc. but it'd be nice to have this without the hassle of a VPN.

It used to be possible to require both password and pubkey authentication (which is a form of two-factor authentication). Unfortunately this was discontinued in newer versions of OpennSSH (I have no idea why).
Strange. You could still probably rig something with a jailshell that requires you to su.
Aren't password-protected pubkeys effective two-factor auth already?
I have seen it in use at one company I did consulting work for. They used SecureID hard tokens in conjunction with a regular password.
I use key-based authentication with password-protected key. I don't (mostly) have to type the password, because OS X is smart enough to store it to keychain (if enabled). I also have FileVault enabled and my login password prompted when resuming from a sleep, so I think my private key is pretty well protected.
Are you saying that OS X remembers your SSH passwords?
No it remembers the password of the private key... On linux, you can get something similar with ssh-agent
I also use ssh-agent on Windows, through msysgit. I think putty also includes some utility that does the same thing.
OS X is using ssh-agent itself, via a launchd monitored socket. Apple's version of ssh-agent is customised to automatically get passphrases for keys from the keychain.
Right. Essentially you get password-free ssh logins without sacrificing (much of) your security.
My friends and I recently changed our server over from password to key-based, and a small unintended consequence came up: I could no longer SSH from my phone! I'm told that I can get my key on my phone somehow, but I've been too lazy to actually do it. Luckily I figured this out before it was important.

Then again, I'm not sure how important that actually is...

TouchTerm on iPhone supports SSH keys.
I'm on a Nexus One with ConnectBot, and I know it supports it, I've just been too lazy to look it up.
iSSH does as well.

What I did was put my key in Dropbox, load it from the Dropbox app, and copy-paste as needed. Then took the key out of my DRopbox when done.

Use password-protected key pairs when you can, passwords where you can't.

And always check the key fingerprints.

Speaking from experience, while keys are more useful, and more secure if universally used properly - I've seen keys bite firms where it hurts much more often than passwords - because people at some level leave an unprotected key laying around, and that key ends up with root level access to a huge array of servers. The argument is made, in the article, that if people won't password protect their keys they are equally likely to email their password - but this doesn't ring true - it's more logical and straightforward for people to understand a password that needs to be kept secure than a keyfile, which is more abstract and they may not understand.

So - does that mean I wouldn't recommend using keys? No - but if you are going to use them, you have to couple that with strict policies regarding usage and rotation.

I use keys for systems where I'm the sole administrator - because I know MY key management practices - but in group situations, we generally stick to passwords as the primary entry point (and then perhaps keys when it comes to accessing clusters of servers - but we tend to treat those clusters as a single functional machine, so keys make sense here)

Wouldn't key + passphrase be at least as secure as a password?
certainly, but you'll have to guarantee that no user has a keyfile without a password, which is harder than checking for weak passwords on your server...
There are a lot of open issues with ssh keys, especially in an internal environment with a lot of end users. Is is difficult to control the distribution of keys or force a key password policy.

1) Users will copy their .ssh directories to every server they have access to so that they don't have to type in passwords. To deal with this:

  a. You can limit where public keys are stored with the AuthorizedKeysFile directive in sshd_conf. Force all keys to be controlled by root and in a central location. 

  b. Implement kerberos so that users don't need to use keys for single sign-on.

  c. only allow keys for functional ids (i.e. mysql), use IP filtering (from=xxx.xxx.xxx.xxx) on the public key to limit key access to a few administrative servers. 

  d. If NFS homedirs are exported to the world, any attacker can mount them and read off the keys from .ssh directories.

Other folks have mentioned brute-force attacks against your ssh daemons on the public internet. If possible, you should think about using a VPN/two-factor authentication to get access to your network or internal gateway servers.
I use one key everywhere, but the private key lives on two places only: a usb drive on my keychain and on a backup floppy. When I sit down at a system, I load the key into the agent and then unmount the usb drive. It seems that the only way the private key could be compromised is if someone breaks into the agent when I'm on the machine or if someone spoofs the connection to the agent (which, if I understand correctly, won't give them the key, only the ability to use the key while the agent is running).

If the usb drive is lost/stolen, there should be no information that reveals which systems it works on. The key also has a very long passphrase, since I only type it once per day, so that should at least make brute force attacks against the key difficult.

This seems like a pretty secure solution to me. What other weaknesses can you think of?

(which, if I understand correctly, won't give them the key, only the ability to use the key while the agent is running)

By design, talking to to the ssh-agent should not give you the decrypted key. However, in reality, anybody that could write to the ssh-agent socket could also ptrace() the agent and find the key in its memory. That would of course require becoming the user you are running ssh-agent as, but that's typically not very difficult.

What other weaknesses can you think of?

A key logger.

Basically, if you don't trust the system you decrypt your key on, all bets are off.

Yeah, talking to the agent on the same system, I agree. But I think the risk of compromising the agent are a lot higher through the forwarded connection (which I use to log into highly populated systems). And I meant that through the connection you shouldn't be able to get the key.

The key logger is a good point, but I basically only log in from my laptop, office computer or home computer. Only if one of those three are compromised, as opposed to one of the innumerable machines I log in to, should that be a risk.