| Having recently had to implement improved password security for a customer who wouldn't read XKCD #936, the internationalization thing was a pain in the ass. They wanted at least 10 characters, and at least one uppercase, one lower, one digit, and one special character. Easy enough with .NET's built-in membership stuff by setting: passwordStrengthRegularExpression="(?=.{10,})(?=(.\p{Lu}){1,})(?=(.\d){1,})(?=(.*\W){1,})" The "\p{Lu}" part handles uppercase characters even in Unicode chars, but Javascript has no equivalent, so I couldn't do client-side validation of that. Should be validating on both ends anyway, but it's still a pain. The real part I hated was having to keep track of users' last N passwords to make sure they didn't re-use them. Since everything's hashed and salted, I just kept a table of previous hashes by user. Seems simple, but MS didn't see fit to include a HashPassword(string plainTextPassword, byte[] userSalt) method in the membership provider, so I had to reverse engineer their password-hashing method to check when they change passwords if it's something that's been used before. Then I realized that they could just change their password N+1 times in about a minute, then re-use their expired password anyway, so we wound up having to set a minimum age of N weeks before a password could be reused as well. The whole problem is an exploding requirements nightmare that could easily be solved by saying "Must be >32 characters and don't write it down anywhere, idiot." The worst part is as much as I hate these types of requirements, I now perfectly understand why these systems are the way that they are. |