Access a password form field only once to validate it and assign it to a variable. After that use only the validated variable.
Use a standard function to check password complexity requirements.
All temporary passwords should have a short expiration period or should be marked as already expired, forcing the user to change the password.
Never place the username on the URL’s query string.
Avoid user directories or other methods that others could use to harvest usernames.
Do not automatically generate usernames or account IDs.
Always use well-established hashing algorithms, such as those included with the System.Security.Cryptography class.
Centralize all encryption code so that you can easily change algorithms and/or keys.
Always check the password age immediately after authenticating the user.
Password changes should be on a page of their own and accept the old password as well as the new password in a single step.
Expire all user sessions immediately after changing a user’s password, requiring the user to reauthenticate.
Treat lost passwords as a security event, taking measures such as logging event details, including client IP address.
Carefully manage session state throughout the reset process; do not track session account identifiers on hidden form fields or query strings.
Never send sensitive information via e-mail.
If possible, use PGP or S/MIME to digitally sign and/or encrypt e-mail communications.
If creating temporary passwords, use a strong random algorithm with sufficient entropy.
Use questions with enough possible answers to prevent guessing or brute-force attacks.
Avoid questions for which many people will select the same common answers.
Avoid long or overly complex URLs, especially at the application entry points such as a login screen.