First of all, I must confess: despite dire warnings to the contrary, I use the same password for more than one web login. But I’m sure everyone does, simply because so many sites require logins that having a different password for each site will be less secure by virtue of needing to be written down or otherwise stored in plaintext. And really, the consequences of getting an account hacked (and the benefits to any prospective hacker) are so low that it isn’t worth bothering. So a hacker can tweak my Delicious bookmarks, or see my bit.ly statistics, or whatever. Big deal.
Even worse, my password for such low-value sites is a dictionary word. Admittedly it’s a dictionary word chosen at random from the Shorter OED, which gives a theoretical 500,000 possibilities. Even if we suppose I ignored overly short words and didn’t choose entirely at random, the odds of someone guessing it have to be one in 200,000 or longer.
This seems reasonable to me, but plenty of sites aren’t having it. As far as they are concerned, protecting me from the consequences of bad password choice is their problem, not mine, and the way to do that is to ensure that my password has at least one digit in it. Or at least four digits. Or maybe a non-printable character. Or at least 2 capital letters. They don’t seem to be able to make their minds up.
So I just do what everyone else does in these circumstances: I use the same password, and make minimal tweaks to satisfy the algorithm. I capitalise the first letter. Or I add a standard number on the end of it (hey hackers, I’ll tell you this for free: I always use the number 12).
Security is always a tradeoff with usability, and the tradeoff here is terrible. Users will always use one of a tiny number of tricks (appending 123, using l33t-sp3ak, etc.) that make minimal increase to the search space. Hackers aren’t greatly inconvenienced, but the user has to remember exactly what set of requirements they were trying to satisfy when they created their password. Here’s a hint to designers: if I find myself having to think hard about what combination of capitalisation and numbering I used when I signed up, and I don’t really like your site, then I just won’t bother logging in again.
But the really dumb thing is that this is defending against the wrong problem. Passwords aren’t typically compromised by brute-force attacks across a large search space, they’re compromised by being human-understandable and relevant to the person that created them (personal names, dates, etc.) Checking the password against common human names and date formats (e.g. 19xx) would be more effective.
And if you’re worried that the web application you’re writing will be subject to brute-force attacks, then it’s easy to defend: limit the rate of queries to human speeds (no more than 5 incorrect passwords per IP address per day) and use CAPTCHAs. Detect suspicious patterns of activity and take action (block the IP address, warn the user being targetted, whatever). Properly implemented, even brute-forcing a mother’s maiden name or a birthday (requiring just a couple of hundred attempts) becomes an uninviting task, particularly when the reward for success is non-monetary.
So why do programmers do this? It’s like the old joke about the drunk who dropped his keys in a dark street and resolved to look for them under a street lamp since the light was better there. Adding rate-limiting isn’t that hard, but it’s orders of magnitude hader than writing a regexp to ensure the password has two digits in it. Even if this doesn’t solve the problem, it gives the impression that we’re making an effort.