4

I'm looking to do some pattern matching for passwords, and found a regex example on SO, but when I pass a password through which should be deemed "strong", I am met with the opposite. For example, the string "JlcimYQF+EkHVA*" yields a rating of 1, which means that the string patterns aren't being matched in the regex, but I am unsure why.

Code below:

public class PasswordAdvisor
{
    public static PasswordScore CheckStrength(string password)
    {
        int score = 1;

        if (password.Length < 12)
            return PasswordScore.TooShort;
        if (password.Length >= 16)
            score++;
        if (Regex.Match(password, @"/\d+/", RegexOptions.ECMAScript).Success)
            score++;
        if (Regex.Match(password, @"/[a-z]/", RegexOptions.ECMAScript).Success &&
          Regex.Match(password, @"/[A-Z]/", RegexOptions.ECMAScript).Success)
            score++;
        if (Regex.Match(password, @"/.[!,@,#,$,%,^,&,*,?,_,~,-,£,(,)]/", RegexOptions.ECMAScript).Success)
            score++;

        return (PasswordScore)score;
    }
}

Deceleration:

var passwordStrengthScore = PasswordAdvisor.CheckStrength(@"JlcimYQF+EkH*VA");

        Console.WriteLine((int)passwordStrengthScore);

        switch (passwordStrengthScore)
        {
            case PasswordScore.TooShort:
                Console.WriteLine("Password is too short");
                break;
            case PasswordScore.Weak:
                Console.WriteLine("Password is very weak");
                break;
            case PasswordScore.Medium:
                Console.WriteLine("OK password");
                break;
            case PasswordScore.Strong:
                Console.WriteLine("Strong password");
                break;
            case PasswordScore.VeryStrong:
                Console.WriteLine("Very strong password");
                break;
        }
  • 4
    Remove `/` delimiters from all patterns. Replace `@"/.[!,@,#,$,%,^,&,*,?,_,~,-,£,(,)]/"` with `@"[!,@#$%^&*?_~£()-]"` to also require one of these special chars. In all but `Regex.Match(password, @"\d+", RegexOptions.ECMAScript)` statements, you may safely remove `RegexOptions.ECMAScript` option. – Wiktor Stribiżew Jun 22 '18 at 10:51
  • Ok, I added the answer to provide more insight. – Wiktor Stribiżew Jun 22 '18 at 10:59

1 Answers1

3

You should remove / delimiters from all patterns as .NET regexes are defined with string literals, no delimiters are required, and these / chars are part of the patterns that do not match what you expect.

You should replace @"/.[!,@,#,$,%,^,&,*,?,_,~,-,£,(,)]/" with @"[!,@#$%^&*?_~£()-]" to require at least one of these special chars. Note that an unescaped - inside a character class between literals creates a range, thus it is safer to put it at the end (or escape it). NOTE: I kept the comma inside, but since you used it as an OR operator, probably, you should remove it completely. The OR relationship is the default one between atoms in a positive character class.

In all but Regex.Match(password, @"\d+", RegexOptions.ECMAScript) statements, you may safely remove RegexOptions.ECMAScript option that only affects shorthand character class (like \s, \d, etc.).

Use

    if (Regex.Match(password, @"\d+", RegexOptions.ECMAScript).Success)
        score++;
    if (Regex.Match(password, @"[a-z]").Success &&
      Regex.Match(password, @"[A-Z]").Success)
        score++;
    if (Regex.Match(password, @"[!,@#$%^&*?_~£()-]").Success) // check if you need a comma here
        score++;
Wiktor Stribiżew
  • 607,720
  • 39
  • 448
  • 563