Yesterday, Troy Hunt
posted a very well written article
showing how account enumeration can cause information disclosure. Essentially, in an attempt to be useful, your site inadvertently tells an attacker who is and isn't a user of your site.
For instance, if you use email address for username, when a user logs in your site has the option to tell them if their email address or password is incorrect. If you are specific: "Email address not found" or "Password incorrect", then account enumeration is possible. I can send my list of 144 million email addresses and a password of 'asdf' to your login page, using ZAP
Fuzzer. Then, those that said the password was incorrect mean that the email WAS correct, and I have a list of valid accounts.
As an aside, 20% of user accounts use the top 100 most popular passwords. If I can bypass your account lockout procedure with timing or parameter tampering, and send those 100 passwords to each of the legit accounts that I have enumerated, I will statistically gain access to one in five. I have tried this four times, and it has worked all four times.
So, anyway, I am here to tell you that simply making sure that you post a 'Your credentials are incorrect' isn't enough., Troy found a really good subtle indicator in his post, and to find those I recommend that you send each response to a comparer - both the failed username and password - to make a bitwise comparison. I have found stylesheets slightly different, an extra linefeed, all kinds of things. But with the prevalence of hashing, I have discovered something even more interesting.
"But Hashing, Bill? I thought hashing passwords was a good thing!!"
You are right.
Let's look at a login procedure. In the POST action, you have something that looks a little like this:
user = LookupUser(username)
if user then:
if hash = user.hash then:
Follow me? If the user exists then hash the password and compare. Seems like a pretty sensible model.
There is a problem, and I discovered it because I usually run tests with F12 tools loaded up. When I passed in the wrong username, the response took about 100 milliseconds. If I passed in the right username and the wrong password, the response took around 500 milliseconds. The time it took to hash that password resulted in account enumeration.
So I tossed my list of email addresses against it with a password of "password". Those that took 100 milliseconds I discarded. Those that took 500 milliseconds were valid accounts.
What's the takehome from this? Well first, get a application vulnerability analysis from a qualified auditor. These things are hard to find. Second, very carefully review the code for your login procedure. For the average attacker, this is the only page that is available for attack. Don't give away the freebies.