10

I have a website and my users will be using their selected password to encrypt their RSA private key using JavaScript client-side. How should I be making sure they are using a strong password without transmitting it to the server?

Peter Mortensen
  • 877
  • 5
  • 10
mark820850
  • 141
  • 1
  • 4
  • 5
    What makes a "strong" password to you? Have you seen all those "password strength checkers" on websites you've used? Those are all client-side. – schroeder Nov 14 '19 at 15:36
  • 2
    Rather than try to estimate password entropy, consider providing users with a strong way to choose passwords automatically which they can then write down, like ten diceware words from a user-selectable choice of a handful of word lists. – Squeamish Ossifrage Nov 14 '19 at 16:30
  • It depends if you trust your users to execute the JavaScript code you send them as intended. Clients can override client-side protections. If you can't trust them, then you don't have a way to do this except brute forcing with known passwords to test if it's any of those. – meneldal Nov 15 '19 at 01:44
  • 3
    You should read Peter Gutmann's *[Engineering Security](http://www.cs.auckland.ac.nz/~pgut001/pubs/book.pdf)* before you go further. In particular, Chapter 7 on Password Security. Pay attention to the discussion of Bloom Filters and weak/wounded password lists. The filtered password list will be small - around 60 KB - and easy to send to a client via JavaScript. You can find weak/wounded password lists at [SecLists on GitHub](https://github.com/danielmiessler/SecLists). –  Nov 15 '19 at 03:33

4 Answers4

26

You can use zxcvbn, which is a JavaScript library that checks password strength.

Alternatively, the HaveIBeenPwned API takes an interesting approach to check passwords without sending the password to the server:

  • Take a SHA1 hash of the password.
  • Truncate it to five characters.
  • Send this to the server.
  • The server returns the full SHA1 hashes of all known (insecure) passwords with these five characters at the start of their hash.
  • The client checks whether the password hash is in this list.

This way, you don't submit the whole password but the client also doesn't need to retrieve the whole password database.

bdsl
  • 595
  • 3
  • 7
Sjoerd
  • 28,707
  • 12
  • 74
  • 102
  • 7
    zxcvbn has it's flaws too, and renders it quite pointless. For instance, it would consider `MakeAmericaGreatAgain` to be a relatively secure password, even though you and me both know it probably isn't. –  Nov 14 '19 at 14:42
  • that is so great first time I hear about HveIBeenPawned, but does it work for real? I mean from cryptographic view Because what I know is when a single letter of hash's input differ then the whole hash will differ – mark820850 Nov 14 '19 at 14:55
  • 4
    @mark820850 The idea behind hveIBeenPawned is that it is *very* cheap for an attacker to check all of those hashes looking for low hanging fruit. If you crack a server enough to get a list of encrypted passwords, you can see if any of them just happen to be the poor choices, and then log in with those. In the same vein, it was common to check whether the password was "password" or "password1", given how cheap that attack was to execute compared to how often it succeeded. – Cort Ammon Nov 14 '19 at 14:58
  • 1
    @mark820850 HaveIBeenPwned (HIBP) works off of having a gigantic list of leaked passwords. They have MD5 hashes of all of those leaked passwords. You send up the first 5 characters of your MD5 hash, and they return a list of all password hashes they have that start with those same 5 characters (typically ~100 hashes). As a result you will get back many hashes for completely unrelated passwords. However, if you find a hash that matches your hash, you know that they have that password in their database and therefore that password has been leaked previously. – Conor Mancone Nov 14 '19 at 16:00
  • 1
    The idea is that if a password has showed up in a previous password dump it is no longer a secure password. Therefore they aren't measuring password strength exactly, but trying to more directly determine if a password is known to be unsafe. They have you send the first 5 letters of the hash because this way you don't actually send around your user's passwords, so this is effectively a private way of checking passwords against a database of leaked passwords. – Conor Mancone Nov 14 '19 at 16:01
  • @ConorMancone on the other hand, using HIBP as a blacklist pretty much means that you have to use randomly generated passwords that are secure but need a password manager; a large portion of rememberable passwords (i.e. a word or two with some special chacter alteration) that your users will try to use *will* be on that list. Requiring your passwords to be essentially globally unique is more secure, but comes at a convenience cost for your users who don't use a password manager. – Peteris Nov 15 '19 at 13:33
  • 1
    @Peteris My comments aren't meant to be an endorsement of HIBP, simply because it isn't the best solution for everyone. In general though I do think it is good advice to avoid passwords that have been in a breach. My suggestion for users that want a memorable password and don't use managers would be to use a pass phrase. Even if it is just 4 words and an actual sentence (i.e. *much* weaker than diceware), as long as it is 12+ characters long it will probably still be a better password than whatever they were using before. – Conor Mancone Nov 15 '19 at 13:57
  • 1
    @Peteris .... Which is a bonus anyways, since pushing more and more users to use password managers is a good thing. – Delioth Nov 15 '19 at 15:34
  • @ConorMancone the pwned passwords API uses SHA1 not MD5 – Greg W Nov 16 '19 at 03:19
9

My go-to for passphrase strength questions is NIST SP 800-63b: "Digital Identity Guidelines: Authentication and Lifecycle Management". While this is a US Gov standard, it also serves as sound guidance for the rest of us.

5.1.1.2 Memorized Secret Verifiers

...

When processing requests to establish and change memorized secrets, verifiers SHALL compare the prospective secrets against a list that contains values known to be commonly-used, expected, or compromised. For example, the list MAY include, but is not limited to:

  • Passwords obtained from previous breach corpuses.

  • Dictionary words.

  • Repetitive or sequential characters (e.g. ‘aaaaaa’, ‘1234abcd’).

  • Context-specific words, such as the name of the service, the username, and derivatives thereof.

If the chosen secret is found in the list, the CSP or verifier SHALL advise the subscriber that they need to select a different secret, SHALL provide the reason for rejection, and SHALL require the subscriber to choose a different value.

Verifiers SHOULD offer guidance to the subscriber, such as a password-strength meter[Meters], to assist the user in choosing a strong memorized secret. This is particularly important following the rejection of a memorized secret on the above list as it discourages trivial modification of listed (and likely very weak) memorized secrets[Blacklists].

Notice how they suggest using strength meters (like zxcvbn) simply as a UI aid, but the actual enforcement is done against a blacklist.

In my experience, the best way to implement this is use a client-side (javascript) entropy-based strength meter like zxcvbn to help the user weed out obviously-weak passphrases. Then when they click Submit, do a REST call to a blacklist database like HaveIBeenPwned. Note that the HaveIBeenPwned API has been designed to avoid leaking the user's actual password, even to the HaveIBeenPwned admins, as @Sjoerd describes nicely in their answer.

Mike Ounsworth
  • 57,707
  • 21
  • 150
  • 207
  • 3
    I'm also glad NIST dropped the "uppercase, lowercase, number, symbols" stuff. Password length is the key thing from an entropy standpoint - the longer a minimum your users can stomach, the better (NIST says 8 as a minimum). Filter out sequences (alpha, numeric, keyboard), use a top-XXXX list of most common passwords (and filter those out), – Joe Nov 14 '19 at 18:14
  • @Joe Agreed! Unfortunately, the HaveIBeenPwned API doesn't lend itself well to a top-XXXX approach -- it tells you how many times the password shows up in his breach db. What I really want is know is its rank, you know, so I can do _"Is it in the 100,000 most common?"_. As it is now, I have to do _"Does it appear more than 20 times across all breaches?"_. [Here's a sample of the API data](https://api.pwnedpasswords.com/range/12345). – Mike Ounsworth Nov 15 '19 at 03:10
  • 1
    Yeah, we had to build our own using lists on the internet and we do it via a round-trip to the back-end. – Joe Nov 15 '19 at 03:16
  • 1
    Why not just disallow any password on the list? After all, that is what the standard you posted suggests, and personally I wouldn't want to use a password even if it had only been leaked once. – Conor Mancone Nov 15 '19 at 13:50
  • @ConorMancone Because usability. According to the site, the HaveIBeenPwned db currently has 555M records. You personally might be willing to keep trying passphrases until you find one that has never before been used (and breached) on the internet, but many users will find that too frustrating. IMO, how deep the blacklist is should be admin-configurable to match the security needs of an organization. – Mike Ounsworth Nov 15 '19 at 18:44
  • To be fair, I just spent a few mins trying things, and almost everything I tried is not in the db. So maybe "Not in the top 555M" is not too onerous afterall. *shrug*. https://haveibeenpwned.com/Passwords – Mike Ounsworth Nov 15 '19 at 18:47
  • I've never tried too hard to see if it would actually be difficult to make a password that isn't in HIPB. Honestly, I never even gave that issue a thought (I don't actually use HIBP in my services, although I've thought about it). 500M sounds like a lot, although I suspect that the number of possible "insecure" passwords is actually so large that 500M is really not a lot. I have no idea in practice though, so it's an important consideration... now I wish there was a way to determine what "fraction" of insecure passwords have been "used up". – Conor Mancone Nov 15 '19 at 18:52
  • 1
    None of my old (now unused) passwords have been pwned, although my old passwords are strong enough and unique enough to me that I wouldn't expect them to be leaked unless the password had specifically been stolen from one of my own accounts. However, definitely don't use `billybob` (the first random dumb password I tried) - been leaked about 30,000 times. That's gotta be an "USA-only" thing... – Conor Mancone Nov 15 '19 at 18:54
  • 1
    @ConorMancone and Mike, I'm citing your conversation as part of [this other question](https://security.stackexchange.com/q/221302/56961) that may be of interest. – Michael Nov 15 '19 at 21:49
  • 1
    @Michael I assume you would see no problems with demanding something much stricter than "your password may consist of lowercase letters only, but please make it longer than 6 characters". That forbids the same order of magnitude as forbidding all 550M records known to the HIBP db – Hagen von Eitzen Nov 16 '19 at 10:14
5

Measuring password entropy is not an easy task, and basically not even feasible to do. Any system or measurement can be circumvented if tried hard enough. If users really wanted, they could probably even get away with using something like .

It's much better to give user guidelines on how to pick a good password, such as:

It is recommended to use a password manager to generate a long, random password and store it in a safe place.

If using a password manager is not possible, it's encouraged to use Diceware to generate a sufficiently good password.

... And so on and so forth ...

  • 6
    ‘Measuring’ entropy given a single password is not merely hard but _meaningless_, without a parametric model for the procedure used to choose the password. However, there is a reasonable question of whether the intervention of _displaying a password strength meter_ (whatever model of strength underlies it, if any coherent model!) has the effect of _convincing people to use better password-generation procedures_. The effect of this intervention is hard to measure, of course! But it's not _a priori_ clear that strength meters—while _conceptually_ absurd—fail to have a useful effect. – Squeamish Ossifrage Nov 15 '19 at 04:59
1

"password strength" is not a clearly defined metric. And when implementing such a checker, please do keep in mind that most libraries still implement the outdated and wrong old NIST guidelines (special characters, numbers, that nonsense).

The strongest indicator of password strength is length. Requiring a reasonably high minimum length, which (2019) is around 12 characters or 16 for important things, is the strongest single check you can have. Mike already included the relevant NIST recommendations for more details.

If you use a library, choose one that implements the current NIST guidelines, not the old ones.

Tom
  • 10,124
  • 18
  • 51
  • 1
    This seems better as a side bit of advice and not an answer to the question about how to do it. – schroeder Nov 15 '19 at 20:29
  • IMHO, length is *not* an indicator of password strength. Consider `ABCDEFGHIJKL`, length is 12, but this certainly **not** a strong password! `b@af$T7@` is shorter (8) and, certainly, much stronger. – Toni Homedes i Saun Apr 05 '22 at 10:58
  • @ToniHomedesiSaun length is better than complexity. Of course you can make a crappy password at any length, i.e. AAAAAAAAAAAAAAAAAAAA - but that doesn't invalidate the point. – Tom Apr 05 '22 at 12:47
  • @Tom I may be wrong, but I don't really agree. For a password to be considered _good_, what you want is high _entropy_, so that it's difficult to guess and brute force. When trying to measure how _good_ a password is, you should try to measure its entropy, which is a function of many things, among which both length and complexity. A good entropy meter should give a close to 0 value to AAAAAAAAAAAAAAAAAAAA. – Toni Homedes i Saun Apr 06 '22 at 13:26
  • 1
    @ToniHomedesiSaun you are assuming that passwords are guessed or brute forced. That is actually fairly rare. Passwords are much more often phished, shoulder-surfed or taken out of compromised user databases that didn't hash and salt them. That said - we seem to agree that A(...) is a shit password. – Tom Apr 06 '22 at 15:19