This post outlines best practices of using old-school passwords. There is a lot of things to consider when designing a system that uses username and password for authentication. First, you should read the following material and only then proceed with this post that is basically a story of authentication with username (un) andpassword (pw) governed with a password policy.
- OWASP Authentication cheatsheet
- Password storage cheat sheet
- Wikipedia article on “password strength”
- Good password policy in the OWASP website.
When your system uses passwords you need to consider:
- Generate and assure good quality passwords with the help of a password policy
- Store passwords securely
- Prevent online brute force guessing attacks with the help of a account lockout policy
- Log and monitor authentication events – especially failed attempts
Some libraries which help achieving this
- Passfault is a tool to evaluate the strength of passwords accurately enough to predict the time to crack. It makes creating passwords and password policies significantly more intuitive and simple.
- Acceptance of strong passwords: zxcvbn
- Storage of passwords and PINs: Scrypt, Bcrypt and ARGON2, see password cheat sheet
- Previously used and leaked passwords: local docker for haveibeenpwned.com/passwords
- Protection from online attacks: using Device tokens or slow enough constant guessing rate (sliding window) for passwords and limited number of guesses for PINs. For example, I have implemented a constant rate password checker that allow N failed login attempts in a minute over one hour period.
- Implement Identity lockout policy including monitoring
- Make password checking fast using bloom filter: https://github.com/jarirajari/have-i-been-bloomed
What makes a good username, password, PIN?
Both are text, but also
username
- -username is an unique and random ASCII string- email address, mobile number, etc. must not be used as a username, but username can be retrieved based on those values
- if removed at system at a point, it must not be reused
- should be given to user although this is not very usable e.g. easy to remember but doable in the time of password managers
password
- recommend and offer a randomly generated strong password
- if user chooses own pw, use ‘zxcvbn’ to advice against poor passwords (based on entropy)
- if user chooses own pw, use have-i-been-pwned to advice against already compromised passwords (https://haveibeenpwned.com/Passwords)
- require using at least 16 char passwords (reference)
- how about pass phrases / mnemonic passwords?
- provide prevention mechanism for brute-force attacks => only constant rate inputs are allowed e.g. 4 inputs per second (4 IPS)
- do not force users to change passwords if they are not compromised
PIN
- from 6 to 9 digits – only digits although a secret can use alphanumeric chars
- system generated so that it is truly random
- provide prevention mechanism for brute-force attacks => allow only 3 inputs before PIN is locked for good
mnemonic
- known from crypto currency world: 12 word (BIP39) mnemonic produces approx. 128 bits of entropy
- basically a string word words separated by a space or a dash
- easier for human to remember. For example 6 words produce approx. 66 bits of entropy which better than many passwords – especially user generated ones
- good for account reset i.e. recovery codes
How to store them properly?
username
inherently public, you can share it. But there can be also more private usernames. Store to database in plaintext. Prevent username enumeration however.
password
Relatively dangerous concept called Pepper. Figure below depicts how Dropbox stores users’ passwords. Their post also highlights that the first create a SHA512 hash from the plain text password. Why? Because they use bcrypt instead of scrypt or argon2, and bcrypt has certain problems. So of course you need to use modern uncracked algos, proper. But also don’t use peppers at least the typical way i.e. more hashing. Salts should be stored separately from the passwords and not in code: e.g. to a HSM or secret vault. In summary, store passwords as hashes. If the actual password needs to be recoverable, then use symmetric encryption algorithms e.g. SHA-256.

PIN
Store as hashes similar to passwords.
mnemonic
Mnemonics should be stored as is because they are used in plain text format. Most often you should store these to password managers.
Recovery and reset
How to reset username, password, PIN, or mnemonic? Let’s start with the obvious one: you cannot change username. For the rest, you need a design. I have designed one that allows you to reset secrets using following mechanism with two-factor authentication
- Reset password: 1) for a registered user it requires registered email address and user PIN. A code is sent to the email address (plain text, not a link) 2) for an unregistered user it requires access to the email and typing in the generated password
- Reset PIN: requires reset secret aka. user mnemonic. Another factor is user session stored in a cookie.
- Reset mnemonic (requires active session): Just ask for a new one but send an email to the known user email. Reset mnemonic can be used to reset all other secrets! Note that user has authenticated using 2-FA!
P.S. Current prices for strongest CAPTCHAs are (ReCaptcha v2): $2.99 per 1000 so 0.003 USD per unit
You must be logged in to post a comment.