iBeta does automated testing of the security of websites, especially for things like cross-site scripting (CSS), and cross-site request forgery (XSRF). However, our automated tool occasionally finds other problems not strictly related to those and not strictly in the OWASP Top Ten.
Caveats: The following analysis is based entirely on a brute-force attack and the results cannot be extrapolated to hackers that are using dictionary attacks or have other knowledge that would help them figure out your user’s passwords.
One of these has to do with the “Login page password guessing attack” that is in the module, Html_Authentication_Audit.script. This script is truly a brute-force attack against a login page, and does not assume that the hacker knows the username of an authentic user of the website. Therefore, even if you lock out a username that is in your database of acceptable users, this particular script has most likely chosen a username or usernames that are not in your database.
Lockout known usernames after failed attempts
First, consider the case that your website locks out known user accounts after some number of failed password attempts. That is, the username entered belongs to a username in your database. After some number of failed logins, your website locks that user out.
Let us assume the following
- Your login page is using TLS or an acceptable variant, so that, for example, if your users are logging in from an unprotected wireless internet café, your login page request is not broadcasting their username and password to the entire café.
- After some number of failed password attempts, you are locking out usernames that you know, at least for some time.
Let there be a hacker! I hereby name my hacker, Hackster. I like to give Hackster perhaps more credit than Hackster is due. The first thing Hackster is going to do is attack the ‘forgot password’ page and see if there is a different response for ‘I cannot find that email address in my list of accounts’ and ‘Hello dude. We sent you a new password!’ If Hackster gets the latter, then he no longer needs to brute force the username, and instead he is going to brute force the ‘forgot password’ page until he has a list of usernames. Suppose Hackster tried that and found out the ‘forgot password’ page was perfect.
Hackster is going to try usernames and passwords both chosen randomly hoping that the combination will hit before the known username lockout hits. Alternatively, Hackster is going to try the same random username with random passwords. What are the odds Hackster succeeds?
Suppose your password policy is weak. You allow 8-character passwords and you do not care what they look like. Hackster has a 50:50 chance of guessing the password after trying 267 passwords. Hackster is no fool and he can easily afford to rent 1000 zombies to attack your website. Supposing it takes 1/5 second to get a response, Hackster will have tried all of those 8,000 million combinations in 18.6 days. Hackster won in less than a month.
Therefore, if the username has an account, it might make sense to lockout that account after, say, 10 bad password attempts. That means that on average across his 1000 zombies, Hackster is going to try a new username every couple of seconds. Hackster may not know during the start of his attack that a lockout will occur, but eventually he will discover that some usernames result in a lockout after 10 bad passwords, while others do not. Hackster will therefore conclude that the usernames that are locked out belong to real users. After that, if the username does not belong to an account, Hackster is also going to stop trying passwords after 10 or 11 bad password attempts, or Hackster is dumber than I thought and is going to waste bandwidth on a futile cause. In the latter case, I would let dumb Hackster do that. Smart Hackster is rolling over to a new username, on the average, every 2 seconds, whether he hit a real username or not. Hackster is hoping for the payoff that one of his combinations will hit. Hackster is trying username and password pairs, so really his chance of guessing is for that combination which is 2615. That means we multiply his 18.6 days by 208 thousand-million to arrive at 3.9 million-million days. Smart Hackster has probably done the math and given up.
Hackster has probably considered whether to hit the site with the 11th password attempt or not. If he does, then he knows whether the account was real or not, but then on the average he has also generated a help-desk call from the real user every 18-36 days. In the latter case, Hackster has a list of real usernames, and can go back after awhile and try another 10 passwords. (Note that there is a clue to your Incident Response Team there. If the user does not call in soon after being locked out, then there is likely an incident in progress or Hackster is also employing social-hacking techniques—those being out of scope of “brute-force”).
Dumb Hackster, however, is generating a help-desk call every 18 days because dumb Hackster forgot to do the math.
Because of the lockout policy, only on real accounts, the website has a reasonable chance of withstanding a brute force attack even with a rather poor password policy. We assumed that the round-trip time was 1/5 second. The calculated days are linear with that time so if the round-trip time is even another 1/5 or 1/10 of that time then the brute-force time does not get a lot better. It does, however, mean that the help desk call frequency will increase by roughly the same factor. Therefore, some attacks could lock out a user every few days.
The previous analysis assumed usernames were relatively simple. Usernames are often case-insensitive, but applying policies to username lengths is not a common practice. Therefore, the username factor of 268 might be as small as 264 or maybe even 263. If Hackster can target the 3-6 range length of usernames then Hackster could be generating 264 times as many lockouts as described above. Instead of one every few days or few weeks, Hackster is generating 25,000 a day! It probably depends on how many short usernames there are. Hackster might run out of all of them in a few days or weeks, but your help desk is swamped during that time!
If your website has a policy against short usernames or requires full email addresses that are unique as username logins, then a lockout policy on an existing username is quite successful at thwarting a brute-force attack even if the login page simply ignores non-existing username attempts. However, as username-complexity decreases, the number of locked out accounts will increase during an attack, and that may be both a concern as well as a flag of an ongoing attack.
If your website is using a lockout-mechanism to mitigate brute-force attacks of the password of known users, then unless the website also locks out usernames that are not in your database in exactly the same fashion then your website is leaking information about the usernames to the hacker.
Mitigation without lock-out
Suppose that you have no lockout on accounts. Is there a way to deal with brute-force attacks without a lockout?
As described above, depending on the turnaround to your site, a poor password policy can result in Hackster breaking in as little as 18 days if Hackster already knows the username of the account.
First, we consider hardening the password policy. Suppose you have a password policy of 12 characters, one of them has to be a number, and of mixed case. Hackster has a 50:50 chance of getting in within a window of 6211 possible tries. That comes out to about 52 million-million-million tries.
Suppose we penalize a bad answer with a time-out. Hackster is not going to stick around waiting for a response unless every response (good or bad) takes the same amount of time. Therefore, suppose our website has built-in a login delay of 2 seconds with a standard deviation of a half-second. In other words, 90% of the time a user is waiting at least a second to log in, and only 10% are waiting longer than 3 seconds (you might even truncate the distribution around those 10%-90% marks, or use a constant delay). Hackster’s machines have to wait 2-1/2 seconds or longer to be more than 70% sure that the login was unsuccessful. We stick with the worst case that Hackster picks 2 seconds because he is not as smart as I thought he was (or your delay is not random). Let us give Hackster a million threads or a million zombies or combination thereof. Since Hackster has to wait at least 2 seconds before moving his thread on to the next try, his thread/machine will wait. Well, with the bad password, Hackster is still going to win in 186 days. With that stronger password, Hackster takes over 3 million years to do the same thing!
Therefore, a reasonably strong password policy combined with a login delay of a few seconds can mitigate a brute-force password attack, and leaks no information to a brute-force username attack as to whether the username belongs to a real user or not.
For purists, the Gaussian distribution of delay times is better, because your internal algorithms may take slightly longer one way or the other, and the Gaussian delay would tend to hide that time difference a bit better than would a constant time delay. Beyond that, you should monitor your logs and if you are under attack then start looking to see if there are IP addresses that can be blocked.
- If your website has a strong password policy, and pauses a second or two before responding to a login attempt (successful or not) then a brute-force attack has a very low probability of success.
- If your website has a lockout policy for known users after some number of sequential login failures, then a brute-force attack has a low probability of success. However, as username complexity decreases, the number of help desk requests to reset accounts increases and could become overwhelming.
- If your website has a lockout policy for know users, then unless the login page responds in exactly the same way to the Xth attempt of an unknown user then your website is leaking usernames to hackers.
- The lockout did hurt Hackster. After 10 failed passwords, Hackster moves on to the next username on the list. However, your phones are ringing and users are inconvenienced. The next step would be to unload the help desk by resorting to a 2ndary failed Xth-attempt login page that asks for mother’s maiden name or presents a CAPTCHA.
The OWASP site discusses a number of solutions to this problem, and today’s blog will summarize them in a table.