What is the best way of ensuring that a user supplied password is a strong password in a registration or change password form?
One idea I had (in python)
def validate_password(passwd):
conditions_met = 0
conditions_total = 3
if len(passwd) >= 6:
if passwd.lower() != passwd: conditions_met += 1
if len([x for x in passwd if x.isdigit()]) > 0: conditions_met += 1
if len([x for x in passwd if not x.isalnum()]) > 0: conditions_met += 1
result = False
print conditions_met
if conditions_met >= 2: result = True
return result
Generally speaking, the strength of a password is determined by three things: the length of the character set used, the length of the password itself, and to a lesser extent, the variety in characters chosen.
So, password meters are not a reliable guide to how likely it is that your password will be cracked but they do seem to nudge people in the direction of creating stronger passwords in general.
On the heels of Verizon's 2017 Data Breach Investigations Report, IT security company KnowBe4 released Weak Password Test (WPT), a free tool for organizations that use Active Directory.
Depending on the language, I usually use regular expressions to check if it has:
You can require all of the above, or use a strength meter type of script. For my strength meter, if the password has the right length, it is evaluated as follows:
You can adjust the above to meet your needs.
The object-oriented approach would be a set of rules. Assign a weight to each rule and iterate through them. In psuedo-code:
abstract class Rule {
float weight;
float calculateScore( string password );
}
Calculating the total score:
float getPasswordStrength( string password ) {
float totalWeight = 0.0f;
float totalScore = 0.0f;
foreach ( rule in rules ) {
totalWeight += weight;
totalScore += rule.calculateScore( password ) * rule.weight;
}
return (totalScore / totalWeight) / rules.count;
}
An example rule algorithm, based on number of character classes present:
float calculateScore( string password ) {
float score = 0.0f;
// NUMBER_CLASS is a constant char array { '0', '1', '2', ... }
if ( password.contains( NUMBER_CLASS ) )
score += 1.0f;
if ( password.contains( UPPERCASE_CLASS ) )
score += 1.0f;
if ( password.contains( LOWERCASE_CLASS ) )
score += 1.0f;
// Sub rule as private method
if ( containsPunctuation( password ) )
score += 1.0f;
return score / 4.0f;
}
1: Eliminate often used passwords
Check the entered passwords against a list of often used passwords (see e.g. the top 100.000 passwords in the leaked LinkedIn password list: http://www.adeptus-mechanicus.com/codex/linkhap/combo_not.zip), make sure to include leetspeek substitutions:
A@, E3, B8, S5, etc.
Remove parts of the password that hit against this list from the entered phrase, before going to part 2 below.
2: Don't force any rules on the user
The golden rule of passwords is that longer is better.
Forget about forced use of caps, numbers, and symbols because (the vast majority of) users will:
- Make the first letter a capital;
- Put the number 1
at the end;
- Put a !
after that if a symbol is required.
Instead check password strength
For a decent starting point see: http://www.passwordmeter.com/
I suggest as a minimum the following rules:
Additions (better passwords)
-----------------------------
- Number of Characters Flat +(n*4)
- Uppercase Letters Cond/Incr +((len-n)*2)
- Lowercase Letters Cond/Incr +((len-n)*2)
- Numbers Cond +(n*4)
- Symbols Flat +(n*6)
- Middle Numbers or Symbols Flat +(n*2)
- Shannon Entropy Complex *EntropyScore
Deductions (worse passwords)
-----------------------------
- Letters Only Flat -n
- Numbers Only Flat -(n*16)
- Repeat Chars (Case Insensitive) Complex -
- Consecutive Uppercase Letters Flat -(n*2)
- Consecutive Lowercase Letters Flat -(n*2)
- Consecutive Numbers Flat -(n*2)
- Sequential Letters (3+) Flat -(n*3)
- Sequential Numbers (3+) Flat -(n*3)
- Sequential Symbols (3+) Flat -(n*3)
- Repeated words Complex -
- Only 1st char is uppercase Flat -n
- Last (non symbol) char is number Flat -n
- Only last char is symbol Flat -n
Just following passwordmeter is not enough, because sure enough its naive algorithm sees Password1! as good, whereas it is exceptionally weak. Make sure to disregard initial capital letters when scoring as well as trailing numbers and symbols (as per the last 3 rules).
Calculating Shannon entropy
See: Fastest way to compute entropy in Python
3: Don't allow any passwords that are too weak
Rather than forcing the user to bend to self-defeating rules, allow anything that will give a high enough score. How high depends on your use case.
And most importantly
When you accept the password and store it in a database, make sure to salt and hash it!.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With