23

I am implementing a system where I need to store passwords in a database (hashed and all). My issue is that the business side requires me to not enforce any constraint on them except length (8 characters minimum), but highly advise to use special characters, uppercase characters or not use your first name. Not following these advises would have liability implications on our side. For example, we would allow a client to use 12345678 as a password, but would not be liable if it gets brute forced. This would require me to have an integer in my database that remembers this for the original password (pre-hashing). Any big no-no in doing this ?

EDIT: Just to clarify, the integer would most-likely be a flag that represent the type of weakness, ie: too simple, commonly known weak password, uses personal information, etc..

EDIT 2: Current solution based on the multiple answers and comments below would be to store an integer with flags that have been bit shifted. This integer would be stored in a separate database and encrypted using public-key cryptography, most likely using ECC.

EDIT 3: This is only viable assuming basic security at lower levels (OS and network) as well as spam prevention. The system would block further attempts for sometimes after multiple failed attempts, password are securely hashed using both a (at least) 128 bits salt and time/memory consuming algorithm (Argon2id in this case).

Final Edit: I have set @steffen-ullrich response as accepted. Lots of very good answers and I appreciate all the reason why I shouldn't do this but I wanted answers on what could go wrong and how one would go about doing it this way (many responses helped form the last edit). The legal aspect was provided to focus on the technical standpoint in light of a requirement I have no control over. My second edit basically describe what implementation would be a 0 compromise way of doing this. Disclaimer: this is pure curiosity and I have no plans to actually deploy this in production for the time being, I would recommend reading comments and chat threads before attempting this as they describe much of the problems and limitations of an approach like this.

3
  • 1
    Comments are not for extended discussion; this conversation has been moved to chat.
    – Rory Alsop
    Apr 13 at 12:35
  • What do you do when the password is weak but your software doesn't detect it as weak? Apr 14 at 15:55
  • 2
    Given a weakness indicator is like an "attack here" signpost, it existing could actually make things worse on the legal side. If someone did actually sue then you would need them to verify account ownership i.e. at that point in time they provide the plaintext anyway by logging in to your ownership verifier which then simply displays the weakness rules that were ignored. Apr 14 at 17:35

12 Answers 12

103

Password hashing (with salting and slowness) is designed to make it indistinguishable from just having the hash if a password is weak or strong. Adding an additional indicator about the quality of the password allows an attacker to focus on the weak passwords and therefore significantly decreases the costs for an attacker.

18
  • 10
    @BinarSkugga: As long as the attacker has no access to the information they can not use it. So you might for example move the information elsewhere. Or encrypt it with public key cryptography and a random salt - keeping the public key for encryption local so that the information can be set on password change, but the private key for decryption out of reach of the attacker so that they cannot retrieve the unencrypted value. Apr 11 at 20:53
  • 25
    +1. I came here to say exactly this. WOW your product managers and lawyers sound like they are more interested in covering their own arses than in protecting their customers. I'll bet this also manifests in other areas of product design. Which company do you work for so I can stay away from your products? Apr 11 at 21:15
  • 36
    @MawgsaysreinstateMonica No, he's saying you shouldn't store anything to indicate whether the password is weak or strong. There should be no "target me, I'm weak" markers.
    – TripeHound
    Apr 12 at 8:03
  • 9
    @MawgsaysreinstateMonica special characters are just snake oil. The password to my password manager consists of spaces and lower-case letters, but it has about 78 bits of entropy - minimum length is definitely useful though. Apr 12 at 8:05
  • 14
    If you are going to encrypt a "weakness indicator", make sure you use a mode of encryption which gives a different result every time you encrypt - even if you are encrypting the same text. (Otherwise the attacker can just run the public-key encryption forwards to find out what "short", "common password", "no special characters", etc looks like and then start by concentrating on the easiest to brute force.) Apr 12 at 8:09
22

I am implementing a system where I need to store passwords in a database (hashed and all). My issue is that the business side requires me to not enforce any constraint on them except length (8 characters minimum)

Translation: how to solve a problem that should not exist.

Not following these advises would have liability implications on our side. For example, we would allow a client to use 12345678 as a password, but would not be liable if it gets brute forced.

Well, even if your problem is purely a compliance issue, there are still some unresolved issues here. In a modern system, you are not supposed to store passwords in clear, but hash them. So you cannot really prove that the customer provided a weak password, since the original password is not known to you. What you are proposing is to store an "indicator of weakness" but it is somewhat subjective. It does not really tell how bad the password is. And what's the point really?

Even on a system that is enforcing strong passwords, you should still thwart brute force attempts. Example: ban the offending IP address for 15 minutes after 5 failed tries, something like that.

In case of a breach, and even if you can demonstrate it was caused by a weak password, shifting the blame onto the customer is not going to be well received.

If things go wrong, and litigation ensues as a result of a breach, you may have to demonstrate you undertook every reasonable effort to keep your systems secure and also protect the customers against themselves. Your password policy fails the test. It is below acceptable standards in 2022. There should be enough online resources you can use to convince the business analysts this is a terrible idea.

If I were in your shoes, I would downright refuse to program that thing or demand a liability waiver.

Remember: if when things go wrong, they will have to blame someone, and the someone could very well be you ("the programmer didn't advise us against the flawed requirements"). It's potentially your job and reputation on the line.

15
  • 14
    The original password is known before it gets hashed by the system, and it can calculate the "weakness" then.
    – Barmar
    Apr 12 at 13:54
  • 12
    The question already says that the passwords will be hashed, why are you assuming they're cleartext?
    – Barmar
    Apr 12 at 13:56
  • 26
    Passwords are never hashed client-side, and it provides no security benefit to do so.
    – Barmar
    Apr 12 at 14:35
  • 2
    @Barmar I agree that client-side hashing is often done out of a mistaken belief that it improves security, when transmitting an unhashed password over an encrypted TLS or SSH connection is already secure. Still, there are some minor security benefits to hashing client-side, such as ensuring the server can't accidentally write the plaintext password to a logfile. It's not implausible for that to happen; one might pass a password to a program via an environment variable, and that program might have a verbose option where it dumps its environment to stdout... Apr 13 at 1:43
  • 6
    @JohnKugelman Yeah, "never" was too strong, but even if it's hashed before transmitting, it needs to be hashed again on the server before storing.
    – Barmar
    Apr 13 at 3:05
5

So I'm going to tell you how to actually do this with no security compromise.

  • Generate a public-private key pair for encryption. Use of RSA is advised.
  • Only give the application the public keypair
  • When given a new password, generate 112 bits of noise, prepend that onto your 32 bits of password weakness flags.
  • Encrypt that with AES-128 using a one-time key generated directly; you only have one block and the key is used once so don't bother with IV.
  • Encrypt the 128 bit key using the public key.
  • Store the resulting encrypted key and data block in the database.

Store the private key offline somewhere; if you need to check if a password is weak, copy those two values and only those two values to your offline computer with the private key and read back the bits and determine the weaknesses.

6
  • Thanks for the suggestion ! I believe I now have a good understanding of the things not to do when approaching this. I like the idea of only using the key when verifying. It would prevent me from using warning in the frontend but it effectively mitigates most of the risks (assuming that key is not compromised of course). Apr 13 at 4:25
  • 1
    How does generating an individual key help? Wouldn't just encrypting the weakness flags plus noise with the public key be equivalent?
    – Davidmh
    Apr 14 at 9:24
  • 2
    @BinarSkugga You can still have a warning at the frontend. Every time the the user logs in, the client side knows the password and can recompute the weakness score and present this information visually to the user throughout the session.
    – Luca Citi
    Apr 14 at 11:26
  • 1
    I'd advise against using a crypto library where "don't bother with IV" is even an option. That sounds way too low-level for anyone who's not a professional cryptographer to be using in production.
    – Ajedi32
    Apr 14 at 20:12
  • @Davidmh: RSA is tricky and too potent for my liking. A naïve implementation of encrypt this known message is too easy to break.
    – Joshua
    Apr 17 at 1:51
4

TL;DR

One of the possible ways to manage risk is to transfer it to a third party. This whole scheme is intended to transfer risk to system users instead of system owners, but introducing a non-standard system with increased inherent risk is likely to have the exact opposite effect. Instead, it is more likely that it will increase both inherent and residual risk without legally or effectively transferring any of that increased risk to a third party.

Why No Reputable Framework Recommends This Approach

There are a lot of anti-patterns to doing this. They include, but are not limited to:

  1. The naive approach to this would require parsing and hashing/encrypting the password server-side, which has its own set of problems when compared to client-side processing.
  2. Being unable to hash and/or salt the password on the client side, unless you deconstruct the password client-side and pass additional information about the password's composition or format as metadata.
  3. As a result of the items above, you can't have a zero-knowledge password system since some elements of the password must be known and stored/computed server-side even if the password is hashed or encrypted client-side.
  4. This whole system creates opportunities for side-channel attacks, creates trails of metadata, and identifies low-complexity passwords for brute-forcing opportunities.
  5. It fundamentally solves the wrong problem by trying to shift risk to the system user rather than the owner of the system. This shift is unlikely to be auditable (and therefore largely unenforceable) unless you essentially break the security of the system even further than what you've already described.
  6. Unless your legal department, auditors, cyber-insurance carrier, and infosec department have all agreed that this makes any sort of business sense, I'd personally put it on par with creating risk in the same way that people who roll their own encryption because they think they can do better than the entire field of peer-reviewed cryptography.
  7. You can't point to a single peer-reviewed standard or widely-accepted security framework that would support this type of password policy.

This list is by no means exhaustive. It's just illustrative of various ways that this approach should be a non-starter.

Accurately Measure Your Business Risk

In other words, you're doing the wrong thing because someone has presumably decided it mitigates some aspect of business risk. Rather than doing that without doing the proper research, and then asking strangers on the Internet for reasons to do it or not, your organization needs to conduct a formal risk analysis to determine if it will measurably reduce your business risk in the first place. The company needs to think about the OKRs and controls involved and how they might apply to the business case.

Assuming that this approach would somehow measurably reduce risk, which is a dubious assumption at best, how do you plan to measure whether the residual risk of this control will be below your organization's risk appetite? How will you ensure that those residual risks (including less tangible risks like reputational harm to the organization) can legally or effectively be transferred to a third party?

The first part of this is really a leadership question, not a technical one. The second part is really a legal question, and can't be answered without the advice of legal counsel or input from the board of directors and/or senior leadership.

The triple-net is this whole thing sounds like you're way out on a limb and sawing vigorously, but your mileage may vary.

See Also

4
  • Hi Todd, thanks for the thorough answer ! The first 2 points confuse me. Our frontend communicates in HTTPS. If both the client's device and our server is not compromised, I believe the risk is mitigated. In the case where the client's device is compromised, a keylogger would negate any gains from hashing client-side. If our server is compromised, well they can just bypass any password. For the other points your brought up, I am neither the one that has the leadership or legal hat but I'll forward your points in my written investigation of this, thank you ! Apr 12 at 23:40
  • @BinarSkugga: I saw a document for an old password protocol that was so sickeningly strong that compromising the server would not get you the actual password. You got a password equivalent that would work on that site if you stole it from active session but even if the user reused that password everywhere the thing you got didn't work anywhere else.
    – Joshua
    Apr 13 at 4:10
  • Maybe but compromising the server means you can just go in the database edit that thing or just delete that service that validates the password and replace it with something that lets everything go through. Hell at that point I would have no interest in the password. Just silently stay on the machine and record requests/responses for a while. Apr 13 at 4:19
  • Point 2 seems to miss that if the password is (salted and) hashed on the client, then the hash becomes the password from the point of view of the server. It would still be necessary to (salt and) hash the password on the server for storage. Apr 13 at 20:04
3

If you really wanted to do this, you could have extra columns in your database.

Password_Hash: CHAR(40)
Uses_Uppercase: Bool
Uses_Lowercase: Bool
Uses_Numbers: Bool
Uses_Symbols: Bool
Uses_More_Than_8_Chars: Bool

But, as others have pointed out - this does create some risk. If an attacker gets access to your database table, they can select all the passwords where Uses_More_Than_8_Chars is False and spend their effort brute forcing them.

Or they can perform dictionary attacks only on lowercase passwords with no numbers and symbols.

A better way might be to alert the user that their password is weak, and ask if they accept liability. If so, store a column on the User table Accepts_Weak_Password_Liability: Bool.

But, again, that's a signal for an attacker.

And, in any case, it doesn't help if the user has a complex password which they use everywhere. Or if they have it on a post-it. Or if they accidentally paste it somewhere.

3
  • 1
    If Accepts_Weak_Password_Liability stored a policy version instead of a bool, you could just populate it for all users; if the password is stronger than required by policy (at the time of setting it) then the policy is irrelevant anyway. This means you can no longer distinguish strong from weak passwords by looking at the database, but you no longer need to.
    – Eric
    Apr 12 at 16:06
  • As an adjustment to have ever so slightly more "security through obscurity", I'd suggest a bit-mask instead of separate, explicitly labeled columns, especially not stored in the same table as the password hash. If a bad actor (or anyone, really) got access to the password hash, you would HAVE to assume they have access to the entire record (including each column indicating "when you brute-force this hash, you can eliminate these from your character pool" :P).
    – Daevin
    Apr 12 at 18:45
  • @Daevin yes it would be the solution. Effectively an integer of bit shifted flags. We would also vaguely name the column in another database entirely. Also looking into encrypting this integer. Apr 12 at 23:27
3

Slight frame challenge. Consider using something like the haveibeenpwned api to check the passwords when they are set or changed. Present a message to the user indicating that they are using a known compromised password, and allow an override if you must (something like typing the sentence "I agree to have my account compromised."). Store hashed passwords for the user for at least one password change (this is your proof after an attacker changes the password that the user was using a weak password).

Do NOT store a weak password indicator, but instead use the previously hashed password to indicate weakness if needed with a simple brute-force attack against the password if needed, with a timed attack using standard word-lists or attack methods. Or, if you must (and I would STRONGLY advise against it for all the reasons provided above and in the comments), store a simple flag indicating the user has bypassed the "pwned password" warning in a separate database/machine, etc. If you MUST go that route, don't label the flag clearly as "idiot user" or "weak password" or anything like that - maybe just a label like "flag1". That flag should NEVER be cleared, if it is ever set, as it indicates the user has AT SOME TIME bypassed the warning, not that their current password is the weak one.

2
  • "store a flag indicating the user has bypassed the pwned password warning " is exactly what you mustn't do, other answers adequately explain why, but in summary, that flag becomes a "break this account first" beacon to attackers
    – Ben Voigt
    Apr 14 at 19:03
  • @BenVoigt I agree completely - I have edited to hopefully clarify that there is a somewhat "safer" means to store the info if you are overridden, but I would still vigorously oppose storing that information if I could, since one should ALWAYS assume that any attacker can read and correctly interpret ALL your source code and not just your hashed password list.
    – Brian
    Apr 18 at 15:57
2

NO. You should not allow weak passwords, nor should you keep a record of a strength arbitrarily allocated to the ultimate password. This becomes problematic for stakeholders that insist on informational level audit trails.

The problem is twofold. Firstly you are conceding that there is a foreseeable risk. Secondly, you are identifying customers with weaker passwords.

You especially should not keep a dictionary with hashes of disallowed passwords, you may have users grandfathered-in. Joining these keys would be trivial. It matters not that you lock their accounts on your system. It may be in use elsewhere. It is however a valid intrusion attempt detection method to test for known "scripted" passwords, just do not hash them, or use some other way.

5
  • 2
    It's very valuable and thus not uncommon to have a dictionary of disallowed passwords. I don't understand your rejection of this recommendation at all.
    – erickson
    Apr 12 at 21:57
  • My issue with this answer is no matter how much security measure we have in place, at the end of the day, if someone uses his phone number as password, the risk is there. Even with enforced password rules, people will use passwords like FirstName_Birthdate. In the light of knowing how oblivious people are to password security, I believe it is simpler to advise them and then put warnings if they don't follow your advice. I might be be mistaken, whcih is why I posted the question. Apr 12 at 23:23
  • 1
    @BinarSkugga I agree in principle. At the same time the app is not going to know these secrets. Number plates, name of pets, amusing ascii art may be in dictionaries, and by all means use a meter or a warning. But storing a score next to customer data is defamatory in the extreme, and even an admission of culpability. maybe keep stats but not linked to the customer.
    – mckenzm
    Apr 13 at 5:15
  • 1
    @erikson, I meant don't keep a dictionary of the hashes.... By all means ban the 50,000 passwords on the list from Mozilla, but don't salt and hash them to do it. If you must salt and hash them to notify the customer, make sure there is adequate separation of duties and a very high level of trust (security clearance) for the individuals performing this work in a secure enclave.
    – mckenzm
    Apr 13 at 5:18
  • @mckenzm while I agree this mechanism can't provide a exhaustive list of all passwords considered "weak", I believe it can catch a lot of them without miss flagging any compliant ones. I can't really speak for the "defamatory" as it seems more of a legal term in this situation. I believe flagging passwords of users (using a secure and robust method) is simply a way of protecting ourselves (and the clients), reduce investigation time in case of a hack and provide constructive documentation to them as to how they could improve their digital hygiene. Apr 13 at 6:50
2

Not a good idea. In a similar fashion, the police could attach written notes to all the house doors in a given neighbourhood, and have that notes state how breach-resistant the door is. The authorities will have a policy that people are allowed to have thin plywood doors, but the authorities are not responsible if burglars break into such houses.

In short, you are trying to use programmatic solution to solve a problem that is actually caused by human factor (certain fraction of users tend to use weak passwords). Potential rubber-hose analysis is also a thing to have in mind. Forcing password requirements to ensure sufficient strength is not a clean solution, and it is frustrating for users, but it does a good enough job at protecting you from liability; let's use it until we invent something better.

1

While you mustn't store complexity notes (since they can be used to target weaker passwords for cracking), you can certainly tell the user that their password is weak when they create it. Scare them with your policy and how you're doing your due diligence in telling them that it's weak and how a breach given this notice places the blame on them.

I think we've reached the point at which passwords should always be generated and managed by a password manager. This means there is never any reason to use a password shorter than 20 fully random printable characters (~92²⁰ possibilities), at least for anything that can properly interface with a password manager (e.g. a website as opposed to your computer's login screen).

0

Actually, since your users don't need to know their "weakness" flags in order to login, there is absolutely no reason to store them in the same database as password hashes. You could store them in a separate data structure, probably even on a different server, and unlike hashes these flags can themselves be encrypted. In that case, they will not be "leaked" if your hash database is compromised.

I'm still not convinced you will ever use those flags in a legal dispute with a client, as they have no additional value. If a customer's account is compromised you can simply ask them what their password was, and if it was "1234567", you can attempt to shift the blame to them in court by claiming their "negligence" or something, with or without your "weakness" flag.

1
  • Thanks for your input. Yes I also believe storing them in a completely separate machine (probably even network) is the best solution here. As for the legal part, I added it as context more than anything, I know nothing about the legal implications. I was provided requirements and had question security wise about them. I'm not really here to talk about the legislative relevance of it haha Apr 13 at 8:41
0

It is impossible to reliable know that a password is not weak. Your algorithms can detect some weak passwords but you can't detect every weak password. Some examples, all of this passwords are weak, would your software detect them as weak?

n]j{No(i,mA$XI.dQNZY
Passw0rd!Passw0rd!Passw0rd!Passw0rd!
MyPasswordThatIAlsoUseInOtherServices12!
bl3iavN74RlOlbXxnW+d9+CGKOSWaeimquy26/DHLPQ
588+9PF8OZmpTyxvYS6KiI5bECaHjk4ZOYsjvTjsIho
1qQ2wQ3eE4rR5tT6zZ7uU8iI9oO0pP
0+Q"W*EçR%T&Z/U(I)O=P
a!00!a00!!aaaa!!00!a!0a0

Just because they are long, have special characters, digits and lower and uppercase letters does not mean they aren't weak.

Since you can't know if a password is strong, there is no point of storing the weakness level.

5
  • I have answered this concern in @mckenzm response. I can't catch every weak password just as well as I can't prevent someone from writing their strong password on a piece of paper and sticking it on the laptop. Not catching 100% of cases doesn't devalue the fact that we can still catch some of the egregious cases. Assuming this information is on a separate network and database and is encrypted, I see this as a net positive to help educate our customers on how to make an actually good password, unlike the password constraints we see nowadays. Apr 14 at 16:17
  • Adding proper frontend warnings with alarming messages will prompt more of a call to action than forcing them to write an ! in their password that they are going to forget. At least, it is my theory based on our customer base. Apr 14 at 16:19
  • I feel like this answer would benefit greatly from explaining why these passwords are weak.
    – user163495
    Apr 15 at 12:16
  • @MechMK1 No. I intentionally left that part out. My point is, you can't detect it. If i would explain why, somebody would check for exactly this versions with low entropy and forgot that there a lot of other passwords with low entropy. (If we assume less than 40 bit is low entropy, then there are a trillion low entropy passwords). Apr 19 at 10:28
  • @12431234123412341234123 but explaining how something can seem high entropy while being low entropy is valuable information
    – user163495
    Apr 19 at 12:55
-1

Why don't you get them to input their email and have it do an authentication process so the system knows it's actually them. Then you don't need any password. Ex. Input your email. -Emails a code- -User enters in code- Allows access

1
  • 1
    Please make sure your attempts at answers actually answer the question.
    – user163495
    Apr 15 at 0:12

Not the answer you're looking for? Browse other questions tagged or ask your own question.