loading...
Cover image for How to Process Passwords as a Software Developer

How to Process Passwords as a Software Developer

nathilia_pierce profile image Nathilia Pierce ・Updated on ・4 min read

Passwords are still the primary method of authentication today, in a form of something you know. Humans are lazy, often resulting in low entropy and reused passwords.

Magnitudes of research and thought have been put into protecting passwords. They are known as the simplest form of a challenge–response authentication scheme.

Because the challenge "What is your password?" is repeated, so is the response, opening the door to possible replay attacks.

Choose the Right Hashing Algorithm

Argon2 is a key derivation function, the winner of the password hashing competition and should be used for new projects. In case it isn't available, use Scrypt. Any other KDF is nonoptimal.

Argon2's "i" variant is resistant to side-channel attacks, while "d" variant is resistant to time-memory tradeoff attacks. "id" is the hybrid variant, resistant to both and suitable for most purposes.

Make sure to use "id" variant of Argon2.

Salt Hashes Properly

Salts are closely related to nonces, however, nonces are for communication protocols, not hashing. Nonces protect against replay attacks, while salts protect against precomputed hashes(aka rainbow tables). It's important to separate them, as they aren't protecting against the same things.

The only requirements of salts are to be unique to each hash and public, however, they should be unpredictable to prevent precomputing future hashes.

A cryptographically secure pseudo-random number generator output of 32 bytes will produce an unpredictable, and unique value.

"Pepper" Hashes Properly

If you've been around the internet, researching password salts, you've probably heard of the "pepper". It is a cryptographic secret(secret key), that must be unpredictable and unique to each application, used in a hash function.

Wait ... sounds a lot like an keyed-hash message authentication code, right? That's because it is. One must be extremely careful implementing "peppers" because it can lead to length extension attacks and nasty problems with Bcrypt.

Argon2 actually implements a secret value in the official spec as an optional argument to act as a "pepper". If you're using an implementation that does not support the secret value, encrypt the hash. If you're not using Argon2, encrypt the hash.

Do not waste your time implementing both a "pepper" and encrypting the hash. You gain no practical benefit. And you might want to store your cryptographic secrets in a hardware security module.

Libraries & Services

You SHOULDN'T be rolling your own authentication system in production, use pre-made libraries and services. But you should learn how to implement them and how they work.

If you're a PHP developer, use the built-in password_hash function. Or even better, use Halite. Be sure to use PHP 7.2 and above. Take note that the default password hashing algorithm for PHP is Bcrypt.

Use Halite to hash then encrypt your passwords. An encryption key is required by the library for storing passwords.

PargonIE\Halite\Password::hash($_POST["password"], $encryptionKey);

Another great post about how you should hash passwords in many different programming languages.

Perhaps a third-party solution?:

Use a Reasonable Policy

  • Maximum length of no less than 128 characters.
  • Minimum length of 12 or 16 characters.
  • Support almost if not all Unicode and whitespace.
  • Decline known passwords via HIBP API.
  • Decline passwords matching the identifier, e.g: email, username.
  • Don't enforce special characters, uppercase, lowercase, symbols, etc.
  • Don't truncate, sanitize, or format their passwords in any way shape or form!
  • Don't prevent them from copying and pasting into the password fields.
  • Don't limit what they can or cannot put into the password fields.
  • Don't require password changes every so often.

What matters most, is the length(more so) and entropy. If you feel still inclined to enforce the character set above, don't. Enforce multi-factor authentication instead, their accounts will be far better with it.

If you enforce that character set, you run the risk of them writing it down, forgetting it, annoying them, or choosing a weak password. You can also cause users to write down their passwords if you enforce password changes.

As pointed out by @nylen , perhaps calculate the Levenshtein distance between the password and the identifier and decline passwords within a dangerous distance. Of course with a reasonable minimum distance.

Finally Encourage Good Practices

Encourage the use of diceware, passphrases, password managers (like BitWarden), and multi-factor authentication(FIDO and TOTP protocols).

Discourage passwords with personal information like names, dates, birthdays, etc. Or sharing them if at all possible.

Notes

  • Protect your communications with TLS 1.2 and newer, the successor to the SSL protocol. Otherwise sensitive information(passwords) will be exposed, rendering your state-of-the-art hashing useless.
  • Do not implement SMS for multi-factor authentication! They're easily exploitable via SIM swap scam, and spoofing phone numbers to obtain verification codes.

Discussion

pic
Editor guide
Collapse
michaeljkelly profile image
Mike Kelly

Good suggestions.. But the best is, there is no need to do this yourself. Use Auth0, AAD, AWS Cognito,... Lots of good Auth as a Service options that allow you to not worry about this. As MFA continues to evolve (are YOU going to write FIDO2 support code?) it makes sense to leverage a service for this.

Collapse
nathilia_pierce profile image
Nathilia Pierce Author

Thank you. Unfortunately, someone has to do it. I'm certainly not recommending every software developer to go out there and implement their own authentication system.

And at the very least, software developers should know how to do it properly / understand how it works and should be, even if they don't implement it themselves.

While people keep suggesting to go use an existing service to solve their authentication problems, what if the developers maintaining the existing services don't implement things correctly?

And using existing services is not always ideal.

Everyone makes mistakes, even the experts.

Collapse
nylen profile image
James Nylen

The downside is these are often a nightmare to debug when something goes wrong. Auth0, I'm looking at you here.

Collapse
sandrinodimattia profile image
Sandrino Di Mattia

Offtopic: James, sorry to hear about your challenges when it comes to debugging in Auth0. If you have any specific feedback on what we can improve or details about the challenges you faced, feel free to shoot over an email to sandrino at auth0.com

Collapse
dpkahuja profile image
Deepak Ahuja πŸ‘¨β€πŸ’»

Great article! I liked the Reasonable Policy part but didn’t quite got why special characters are not enforced.

For other readers extended reading (curious or otherwise): i wrote an explanation of salt and peppers (Web Authentication Universal Prinicpals) for software developers. I cover the coding angle of it with in depth illustrations and example.

dev.to/dpkahuja/learn-and-build-we...

Collapse
nathilia_pierce profile image
Nathilia Pierce Author

Thank you!

If you enforce that character set, you run the risk of them writing it down, forgetting it, annoying them, or choosing a weak password. You can also cause users to write down their passwords if you enforce password changes.

I don't know how many times I've been annoyed dealing with that. It should stop at the length requirements, checking for known passwords, and passwords as identifiers.

Simply put, it can have a bad impact on UX, often gaining no benefit, or doing the opposite.

Beyond a minimum and maximum length, password rules are pretty terrible, despite what the math may say about a brute-force attack for those short complex passwords. History should tell you those short complex passwords are not good.

Collapse
dpkahuja profile image
Deepak Ahuja πŸ‘¨β€πŸ’»

Yes. And one more thing in UX i have seen, they tell you after your first password creation attempt what is expected from it. Quite a bummer

Collapse
italypaleale profile image
Alessandro (Ale) Segala

I'd also like to point out that the NIST too recognizes that password complexity requirements are not a good thing: pages.nist.gov/800-63-FAQ/#q-b10

Collapse
cullylarson profile image
Cully Larson

What do you think about comparing the password to a list of X most common passwords and not allowing it?

Thread Thread
nathilia_pierce profile image
Nathilia Pierce Author

I think it's a good idea, as I suggested in the article.

Decline known passwords via HIBP API.

Collapse
brianverm profile image
Brian Vermeer πŸ§‘πŸΌβ€πŸŽ“πŸ§‘πŸΌβ€πŸ’»

I love the article, I think it is a good read and dev should know these principles.

However, I think when possible you should use things like an OIDC provider when applicable, especially if you want MFA.

If not and you need to hash password yourself, find a well-vetted library that does this for you including salts, peppers and fried unions ;). Crypto is hard and nobody should implement it themselves unless you are a crypto genius and many devs (incl myself) are probably not.
You do have to keep the libraries up to date of course.

Anyway, great write! Love the way you explained things. Thanks!

Collapse
phlash909 profile image
Phil Ashby

I agree - great article :)

Regarding the use of federated authentication via protocols such as OpenID Connect (OIDC), I would say it depends on the application context: in a large number of commercial / enterprise situations, then it's very helpful to plug into a companies existing SSO solution where your app becomes part of their suite of tools and doesn't add to their user management pain - a big selling point IMO; in high security scenarios (eg: SIEM access, board meeting record system, privileged access management) or otherwise isolated environments (eg: air-gapped NOC/SOC tools), then it may not be possible to connect to an SSO solution, and it's good to know how to create a trustworthy local authenticator.

Collapse
nylen profile image
James Nylen

What about simple variations of the username, like myusername with password myusername46? I know for a fact that attackers are looking for this common pattern.

I think enforcing a minimum Levenshtein distance between the username/email and the password would be a reasonable measure, but I haven't seen this done before. I'd probably also consider sorting the characters first to catch reversals and other permutations. Do you see any problems with this?

Other simpler techniques such as a substring match would not be such a good idea because a long password that contains a short username should be fine.

Collapse
nathilia_pierce profile image
Nathilia Pierce Author

Great question! That's an extremely good idea, although I haven't seen this done either. I'm sure someone's already implemented Levenshtein distance calculators in various programming languages.

Something definitely to look into. It's no worse than checking if the password is known, as long as the required Levenshtein distance is balanced, but not sure what that would be.

Collapse
hefaistos68 profile image
Hefaistos68

Very nice article. Though you forgot one very important rule: "use adequate measures for the purpose." One of the worst things a dev can do is like enforce a 15 char password with numbers, upper and lowercase letters and at least one special char for an kids account to a game where I dont even have the option to buy anything. If thats for my bank account, ok, I get pissed but understand the idea.

Collapse
sonnk profile image
Nguyen Kim Son

Nice article on these difficult concepts! At the same time I think for most of applications, it's better to not ask user to create yet another password. Most of users don't use password manager and reuse the same password. I wrote an article to actually discuss about this point:
dev.to/simplelogin/why-you-shouldn...

Collapse
nathilia_pierce profile image
Nathilia Pierce Author

I agree with you! However, solutions like SQRL seem like a much better approach to replacing passwords. Where the client is in control of their data, instead of a third-party.

Identity providers can be convenient, but back when I was an average user, I never once used them. Perhaps that's just me, even before I was security and privacy-oriented I tried to never have my stuff all linked up to one account.

I think the future is developers writing installable applications (leaving the clients in control of their data) that are free(as in freedom), open-source, and decentralized(distributed).

Lately, it's just been scary with how much information is collected about us.

Simply put, I think your solution(and nearly all identity providers in the form of third-party servers) is half-solving current problems, but for us to move forward we need to push harder.

And I can see applications being built in the future probably not too far, that are easier to use than SQRL, probably again in the form of asymmetric key cryptography.

This article is especially for you, for people and services who store credentials.

Collapse
sonnk profile image
Nguyen Kim Son

Thanks for your insights! Ease of use is very important and that's the main reason why OpenID 1.0 is replaced or SQRL is not popular.

I don't know about the roadmap of other identity providers but for SimpleLogin, we want to make it open-source so that anyone can setup one for themselves if they want to have total control on the data.

Collapse
leonblade profile image
James Stine

I'm going to look at this as my current defacto password resource. I don't deal with a lot of user creds, but I always find myself looking for what the best algorithm I should use is, or how I should salt hashes. Also, I never heard of "pepper" before, but I guess I shouldn't be surprised because of how much programmers love to give names like this to things. Thanks for the article!

Collapse
nathilia_pierce profile image
Nathilia Pierce Author

You're welcome! And yes, developers do that. "Pepper" is just a cryptographic secret used to make an HMAC in terms of password hashing. Therefore it isn't actually a "pepper". Merely a nickname. :)

Collapse
johnphamous profile image
John Pham

Great article! Should also mention you should transport passwords through a secure line.

Don't prevent them from copying and pasting into the password fields.

πŸ’―, I've always wondered why some websites prevent this action

Collapse
nathilia_pierce profile image
Nathilia Pierce Author

Thanks! I'll be sure to add that.

Collapse
andreasjakof profile image
Andreas Jakof

It’s a bit Alu-Hatty, but right! As the saying goes: just because you are paranoid, does not mean, they are not after you. 😬

Just kidding... very well written and absolutely true. Especially about the character set. Passwords are the ONE case, where length (and I’d say only length) matters.

Collapse
nathilia_pierce profile image
Nathilia Pierce Author

Thank you! And yes, length(more so) and entropy are what matters.

Collapse
optiklab profile image
Anton Yarkov

Very interesting article. Thank you! I wish to have this info updated every 6 months, so developers could easily have an update about recent hashing algorithms just invented or ready-to-use in production. Also, it would be nice to add list of libraries/frameworks for different programming languages that support such hashing algorithms out of the box. It's not always possible to track this information when you deeply work on the product or features, but it's important.

Collapse
failedchecksum profile image
FailedChecksum

I would go so far as to strongly recommend against engineers implementing the password hashing routine for themselves. That requires some additional knowledge like how many rounds to use, memory optimization and how to avoid edge cases that open you to attacks (e.g. Argon2i with 1-2 passes, bcrypt as mentioned). While they should understand the principles it's best to rely one of the many robust, tested, peer-reviewed libraries that exist for most platforms.

re: TLS
Thankfully as of 2020, the browser-based internet effectively won't function on anything less than 1.2. It's about damn time :) Doesn't protect headless clients, but it's a step in the right direction.

Collapse
nathilia_pierce profile image
Nathilia Pierce Author

Agreed, developer shouldn't even be doing the password hashing. I entirely forgot about the 1-2 passes issue with Argon2i, thanks for reminding me. And yes, it's about time we get TLS 1.2 and newer pushed to everybody.

To mitigate the attack there needs to be 3 or more passes with 10 or more passes over memory.

And again, too complicated for your average web developer who barely do any math in their day-to-day job who've got deadlines to meet. :)

I'm trying to find more edge cases, but no avail. Although I've already done massive amounts of research, trying to put together a post with everything about passwords and all the edge cases that come with is a little difficult. There is definitely a long list of issues and practices to avoid.

Collapse
martinscheringa profile image
Martin Scheringa

Why not use SMS?, see Note: Do not implement SMS for multi-factor authentication!

Collapse
nathilia_pierce profile image
Nathilia Pierce Author

Because it's easy to do SIM swam scams, spoof phone numbers, etc. It's another personally-identifying bit of information that we shouldn't need for authentication.

As attacks become more efficient, we're moving to better solutions like YubiKeys and TOTP-based authenticator apps. Both of which are still fairly easy to use.

Collapse
phinor profile image
Philip Norton

SIM swaps can be done without the user's knowledge or consent and thus SMS codes are possible to intercept.

Collapse
italypaleale profile image
Alessandro (Ale) Segala

This is a very good article, but one thing I'd like to point out is that if you're allowing Unicode passphrases (which in itself is a good idea), you definitely need to normalize them (to any form you wish, as long as it's consistent) before hashing them. Otherwise, you risk ending up with different hashes that don't match just because the Unicode representation of the password is different.

I wrote an article about the need for Unicode normalization a few months ago: withblue.ink/2019/03/11/why-you-ne...

Collapse
stremovsky profile image
Yuli

Great article.

For lazy guys, PHP has password_hash() function to hash passwords. It will automatically generate salt value for you.

Best
cloudinvent.com/

Collapse
martian_bold profile image
Martian Bold

Nice article Nathilia!
Greetings from Brazil.
Thank you!

Collapse
kenystev profile image
Kevin J. Estevez

such a great post! the use of password managers is awesome, I've been using it by a while and there are so much good benefits on it, even the auto generated random password functionality

Collapse
theweeappshop profile image
Tony Ross

Awesome article Nathilia, thank you!

Collapse
domthewop profile image
π”»π• π•žπ•–π•Ÿπ•šπ•” π•„π•–π•£π•–π•Ÿπ••π•’ β“‚

Excellent work in breaking down the policies and reasons behind them. There's lots of work to be done by existing companies, but your ground-up approach of educating developers is great. Kudos to you!

Collapse
bokiperic profile image
Bojan Peric

Great article! I think that already a combination of minimal length (12-16) and MFA drops chances of password cracking significantly :)

Collapse
aaronngray profile image
Aaron Gray

Try double hashing once on the client and once on the server ;)

Collapse
nathilia_pierce profile image
Nathilia Pierce Author

Would you care to share if this is good, bad, and why we should or shouldn't take this approach? In most cases, I don't see this adding much benefit.

Although, I could be wrong.

Collapse
canvasbyte profile image
CanvasByte

I always wondered what salt and pepper are, great explanation, thank you

Collapse
nathilia_pierce profile image
Nathilia Pierce Author

Glad to help. :)