Most web applications use username/password combinations to manage access.
To keep password-based login mechanisms secure
- Do not store plain-text passwords, store only hashes
- Use scrypt, bcrypt, or some other hashing algorithm specifically designed for secure password "storage".
- Use a secure hashing algorithm (e.g. SHA-256 as of 2011)
- Use per-user salts
- Use strengthening (i.e. multi-iteration hashing to slow down brute force attempts)
- Limit login attempts per IP (not per user account)
- Enforce reasonable, but not too strict, password policies
- If a password reset process is implemented, make sure it has adequate security. Questions like “mother’s maiden name” can often be guessed by attackers and are not sufficient.
Users re-use passwords for multiple services. If an attacker gains access to one server and can gain a list of passwords, he may be able to use this password to attack other services. Therefore, only password hashes may be stored. Secure hashing algorithms are easy to use in most languages and ensure the original password cannot be easily recovered and that wrong passwords are not falsely accepted.
Adding salts to the password hashes prevents the use of rainbow tables and significantly slows down brute-force attempts. Strengthening slows both off-line brute-force attacks against stolen hashes and on-line brute-force in case the rate limiting fails. However, it increases CPU load on the server and would open a vector for DDoS attacks if not prevented with login attempt limiting. A good strengthening can slow down off-line brute-force attacks down by a factor of 10000 or more.
Limiting login attempts is necessary to prevent on-line brute-force attacks and DoS via the CPU usage of the password strengthening procedure. Without a limit, an attacker can try a very large number of passwords directly against the server. Assuming 100 attempts per second, which is reasonable for a normal web server, no significant strengthening and an attacker working with multiple threads, this would result in 259,200,000 passwords tried in a single month!
Not enforcing any password policies will lead to too many users choosing “123456”, “qwerty” or “password” as their password, opening the system up for attack. Enforcing too strict password policies will force users to save passwords or write them down, generally annoy them and foster re-using the same password for all services. Furthermore, users using secure passwords not matching the policies may be forced to use passwords which are harder to remember, but not necessarily secure. A password consisting of 5 concatenated, randomly (!) chosen lowercase dictionary words is significantly more secure than an eight-character password consisting of mixed case letters, numbers and punctuation. Take this into account if you do not get a password policy to implement, but have to design your own.
If an attacker cannot obtain the password, he may try to reset it. Often, answers to password reset questions are easy to find or guess. Questions alone are no sufficient protection. Consider using a question together with e-mail verification by sending a new temporary password, for example.