Further Password Discourse - Better Practices
by Modus Mundi
"I'm edumacated on every threat in the trade, started checking the checker for any legerdemain" - Aesop Rock, Legerdemain
Hello again.
At the end of my last article (41:1), I asked a bunch of annoying questions, and I'm sure it all felt like a setup - because it was! We'll run down some of the questions I put out there at the end of the article. Onward.
Should We Even Hash?
Something I didn't do in my first article was define what hashing is, or why we might hash over perceived alternatives. Real quick, when I talk about hashing, I am referring to the use of a Cryptographic Hash Function (CHF) on a given string. NIST's definitions of a CHF1 are interesting and generally all say the same thing.
Let's talk about alternatives. A few that stick out are:
- Leave the string plaintext.
- Obfuscate the string.
- Encrypt the string.
To be clear - leaving a password in plaintext is a real bad idea.
If an attacker breaches the system, they then have the plaintext representation of the password that they can then try on other systems. This terrible practice would permit credential stuffing attacks by default, which a security practitioner does not want to do. Obfuscation of the string, such as through some encoding mechanism, does little to dissuade an attacker. A smart attacker will determine the method of encoding and will ultimately decode - unless of course you're using the English alphabet only and ROT262, in which case you have ascended beyond this realm of minimally-crenulated bipeds and probably do not need this article.
Encryption, while tempting, is a path to madness. An unaware reader may be asking "Aren't they the same? and to that I would make a grumpy face. Without going into a rabbit hole, the key difference between encryption and hashing is that encryption, given sufficient inputs, is reversible. This sort of reversibility is crucial for being able to archive sensitive data in a backup.
Having the capacity to reverse a given encrypted string sounds great, until we come to understand that the system that is doing this encryption and decryption must have the tools to do so available. Maybe this means the encryption parameters are local, backed by some HSM and the program we're utilizing is calling out to it, or maybe something completely different - there is a way to call back to the decrypter. A persistent, skilled attacker can and will find that path to reversal and exploit it. As a builder of systems, consider what a reversible string really gets you before you do it. I advise you to generally avoid this. You might think to yourself "I have a valid case," but please. Reconsider. It is likely that you can do what you need without a reversible string.
What Should We Even Hash With?
A problem with password hashing (also, a problem with life) is "what is best" depends on who you ask.
If you're the U.S. government, you rely on the Federal Information Processing Standard, or FIPS. FIPS gets very specific about what can and cannot be used - and updates slowly, even if there have been significant advancements in the field that would give stronger passwords (or communications that are more resistant to attack). If you're in a different country, the government may have radically different cryptographic requirements (for instance, the Chinese government officially standardized SM3 for hashing passwords).
I say this to point out that there will be many constraints depending on where you're standing, and if any of this applies to an actual business. If it doesn't, and it's just you out there in the wild, I would implore you to at least follow local laws around what can and cannot be used (if there are any). Don't be stupid with the law, folks.
There is a mountain of information out there about different hashing algorithms, and you as consumers of information should explore it. If you are not constrained by such things as government or industry requirements, there are smarter people than me offering guidance based on rigorous testing and analysis.
For instance, from 2013 to 2015 there was a password hashing competition held that generally found Argon2 to be the best3. You may be thinking "It's been over ten years; hasn't something better come out?", and that is a valid question. This humble author is unsure; despite researching the topic for some time he has been unable to find an algorithm that is more widely regarded as "the most secure" or "better than" Argon2. This isn't to say it does not exist, but merely that I have not found it. It may still exist in the realm of crypto-wonk academia, which is beautiful and valid.
Should We Rotate Passwords?
Consider that your average user really hates change.
They want a predictable experience and predictable outcomes. They also generally are going to be as low-effort about security initiatives you put in place as they can be. So let's assume your organization has a password policy in place:
- At least eight characters.
- One character must be an uppercase letter.
- One character must be a lowercase letter.
- One character must be a number.
- One character must be a special character.
- Password rotates every 60 days.
The average user of this system will not be enthused, having to change their password every two months. Indeed, the particularly lazy may do something like the following to be compliant and maintain compliance with their passwords:
- Summer1!
- Summer2!
- Summer3!
- Summer4!
And so on.
Your humble author can attest to seeing bad password practices such as this in the wild. On the other hand, we need to keep in mind that not forcing a user to reconsider their password can lead to compromise if they have used that password elsewhere. While I'm not here to tell you never to reset a password, I would offer that NIST's guidance per the 800-63 is pretty solid here; if someone may have gotten in, rotate it and rotate all of them ASAP. This guidance works for a vast majority of use cases and allows you to push password requirements comfortably.
All of that said... some environments may indeed be sufficiently high-impact that you need rotation (maybe even as short as 60 days!), but it is less likely. When in doubt, follow your industry/legal guidelines.
What Is Password Strength Anyway?
Without getting too insane, the "strength" of a password is a representation of how hard it is to determine through whatever cracking means is being used.
A weaker password will be faster to crack than a stronger password. There have been a number5 of papers6 and implementations7 that go into this, and they need to be mentioned here so that you may stand on the shoulders of giants.
To offer a short summary, password strength matters and is a combination of a bunch of factors. Research differs, but generally you want to ensure the password is at least one character class (this means alphabet characters, numerics, or special characters), at least 12-characters long, and has a password complexity that is estimated to require 1010 guesses.
For instance, we might consider the string modusmundi, which by using the aforementioned implementation7 we see has an estimated guesses_log10 of 8.57.
The string Frühjahrsmüdigkeit scores an estimated guesses_log10 of 18.
Perhaps this is because it is not a dictionary term it has access to, but a smart attacker might. A perhaps easier-to-remember string of capslockiscruisecontrolforcool has a guesses_log10 of 20.00652.
I say all of this to emphasize that length matters. Beating heuristics matters. Not much else seems to, from the research.
Thinking About Password Resets
There is a lot to get wrong with resetting passwords, and with account recovery in general.
I'm not going to bore you too much, as there is a blistering amount of good information out there from people smarter than me8, but I will offer a few points I have experienced as a practitioner of the dark arts of identity.
A trap that people get into when thinking about password resets is they want to be helpful. Do not be helpful. Do not let the attacker know if they are expecting a password. The response message for a successful password reset flow initiation should be the same as an unsuccessful password reset flow initiation; that is to say, something boring and along the lines of "If you're in our system, if you own the account you will receive more instructions."
Reset flows should also take care to take the same exact time between a bad user request and a good user request. Reset flows should also take place as out-of-band as is possible, relying on a second factor of authentication where possible. (Some people are going to argue that an email is "something you have" and this works until a RAT is installed on the PC you bank and post cute cat pictures from). Reset flows should log people out immediately and everywhere if they have been successfully activated, and those same flows should notify the user it happened. I've seen what happens personally when these aren't implemented and, while there are other points, I feel like these aren't talked about enough.
While We Are Talking About Time...
As mentioned a moment ago, your password reset flow should take the same amount of time to fail as it does to succeed.
The actual process of authenticating to a service is a whole different story. The hashing method used will drastically impact the speed by which a hash is generated and in turn will impact the time it takes to either crack a hash offline or have a server simply construct a hash of a given string. An MD5 hash, for instance, will be generated significantly faster than SHA-512.
Modern hashing methods, such as Argon2, offer the capability to change settings such that you can change the work factor. This means for a given piece of hardware, the CPU and memory usage of the hashing method can be tweaked to get certain time-oriented outcomes. There are no hard and fast rules here with respect to tuning the hashing method.
Instead we should understand that as we increase the time it takes to hash a given string that time cost is passed on to the service, and to the users. This can cause significant performance bottlenecks and service failures, all for the want of security!
The Argon2 specs paper9 and IETF spec10 gives some food for thought, and OWASP11 gives some good starting points. You'll see in a lot of modern service architectures people want to set Argon2 such that the hashing process takes anywhere from 250 ms to a full second on the hardware they have provisioned to. This makes the parameterization important, as well as understanding the hardware being provisioned to.
With the rise of containerization, this becomes interesting, as 500 millicores of a CPU in 2025 will be nowhere near what 500 millicores will be in 2030, and individuals tuning these parameterized hashing functions will need to reassess their processes on a fairly regular basis. An astute reader might note that a problem we see with passwords is that the very math used to make them secure becomes trivial for future computing environments to, well, compute.
This means responsible system owners are locked in a fairly steady arms race wherein they are moving to newer and better CHFs, updating systems to maintain relevance in the face of new standards/ requirements, and keeping abreast of what nefarious folks with too many GPUs on hand are able to do.
This also means at least keeping an eye on such things as quantum computing and post-quantum cryptography, as at some point (perhaps soon) organizations will need to move to such systems and algorithms as simply the next stage of the arms race in securing systems.
Stay learning. Build better answers.
- Cryptographic Hash Function
- ROT26.org
- Password Hashing Competition
- NIST Special Publication 800-63: Digital Identity Guidelines FAQ
- Guess Again (and again and again): Measuring Password Strength by Simulating Password-Cracking Algorithms
- Practical Recommendations for Stronger, More Usable Passwords Combining Minimum-Strength, Minimum-Length, and Blocklist Requirements
- zxcvbn A password strength estimator inspired by password crackers.
- Forgot Password Cheat Sheet
- Argon2: The Memory-Hard Function for Password Hashing and Other Applications
- The Memory-Hard Argon2 Password Hash and Proof-of-Work Function
- Password Storage Cheat Sheet