web-dev-qa-db-ja.com

パスワード検証の正規表現

現在、この正規表現を使用して、文字列がいくつかの条件に適合するかどうかを確認しています。

条件は、8〜15文字の文字列でなければなりません。文字列には少なくとも1つの数字が含まれている必要があります。文字列には少なくとも1つの大文字を含める必要があります。文字列には少なくとも1つの小文字を含める必要があります。

(?!^[0-9]*$)(?!^[a-zA-Z]*$)^([a-zA-Z0-9]{8,15})$

ほとんどの場合は機能しますが、特殊文字は使用できません。この正規表現を変更して特殊文字を許可することを歓迎します。

45
desi

ここには多くの混乱があるようです。私がこれまでに見た答えは、1 +数字/ 1 +小文字/ 1 +大文字ルールを正しく強制しません。つまり、abc123123XYZ、またはAB *&^#は引き続き受け入れられます。すべて小文字、すべて大文字、またはすべて数字を防ぐだけでは不十分です。それぞれ少なくとも1つの存在を強制する必要があります。

以下を試してください:

^(?=.*[a-z])(?=.*[A-Z])(?=.*\d).{8,15}$

少なくとも1つの特殊文字も必要な場合(これはおそらく良い考えです)、これを試してください:

^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[^\da-zA-Z]).{8,15}$

.{8,15}は、必要に応じてより制限することができます(たとえば、\S{8,15}は空白を許可しません)。ただし、そうするとパスワードスキームの強度が低下することに注意してください。

このパターンをテストしましたが、期待どおりに機能します。 ReFiddleでテスト済み: http://refiddle.com/11


編集:1つの小さなメモ、easiestの方法は3つの別個の正規表現と文字列のLengthプロパティ。また、読みやすく保守も簡単なので、オプションがある場合はそのようにしてください。ただし、これがマークアップの検証ルール用である場合は、おそらく1つの正規表現に固執しています。

79
Justin Morgan

正規表現は、明白な方法よりも単純な制約を強制するためのより簡単/より良い方法ですか?

static bool ValidatePassword( string password )
{
  const int MIN_LENGTH =  8 ;
  const int MAX_LENGTH = 15 ;

  if ( password == null ) throw new ArgumentNullException() ;

  bool meetsLengthRequirements = password.Length >= MIN_LENGTH && password.Length <= MAX_LENGTH ;
  bool hasUpperCaseLetter      = false ;
  bool hasLowerCaseLetter      = false ;
  bool hasDecimalDigit         = false ;

  if ( meetsLengthRequirements )
  {
    foreach (char c in password )
    {
      if      ( char.IsUpper(c) ) hasUpperCaseLetter = true ;
      else if ( char.IsLower(c) ) hasLowerCaseLetter = true ;
      else if ( char.IsDigit(c) ) hasDecimalDigit    = true ;
    }
  }

  bool isValid = meetsLengthRequirements
              && hasUpperCaseLetter
              && hasLowerCaseLetter
              && hasDecimalDigit
              ;
  return isValid ;

}

制約を変更する必要がある3年後の保守プログラマーは、より簡単に理解できると思いますか?

42
Nicholas Carey

この方法を試すことができます:

private bool ValidatePassword(string password, out string ErrorMessage)
    {
        var input = password;
        ErrorMessage = string.Empty;

        if (string.IsNullOrWhiteSpace(input))
        {
            throw new Exception("Password should not be empty");
        }

        var hasNumber = new Regex(@"[0-9]+");
        var hasUpperChar = new Regex(@"[A-Z]+");
        var hasMiniMaxChars = new Regex(@".{8,15}");
        var hasLowerChar = new Regex(@"[a-z]+");
        var hasSymbols = new Regex(@"[!@#$%^&*()_+=\[{\]};:<>|./?,-]");

        if (!hasLowerChar.IsMatch(input))
        {
            ErrorMessage = "Password should contain At least one lower case letter";
            return false;
        }
        else if (!hasUpperChar.IsMatch(input))
        {
            ErrorMessage = "Password should contain At least one upper case letter";
            return false;
        }
        else if (!hasMiniMaxChars.IsMatch(input))
        {
            ErrorMessage = "Password should not be less than or greater than 12 characters";
            return false;
        }
        else if (!hasNumber.IsMatch(input))
        {
            ErrorMessage = "Password should contain At least one numeric value";
            return false;
        }

        else if (!hasSymbols.IsMatch(input))
        {
            ErrorMessage = "Password should contain At least one special case characters";
            return false;
        }
        else
        {
            return true;
        }
    }
10
Anurag

私はそれが次のようになるはずだと思う:

(?!^[0-9]*$)(?!^[a-zA-Z]*$)^(.{8,15})$

これにより、文字クラスの制約が確認され、8〜15文字であるかどうかが確認されます。制約が一致していることをすでにチェックしているため、どの文字が問題になることはありません。

3
Daniel Hilgarth

それらを1つずつ確認します。つまり、番号を探します\d+、それが失敗した場合、数字を追加する必要があることをユーザーに伝えることができます。これにより、ユーザーに何が問題なのかを示すことなく「無効」エラーを返すことを回避できます。

2
Alex K.

これを試してください(大文字と小文字のチェックも修正しました。[a-zA-Z]としてグループ化したため、バグがありました。少なくとも1つの小文字のみを検索します。

(?!^[0-9]*$)(?!^[a-z]*$)(?!^[A-Z]*$)^(.{8,15})$

更新:正規表現が実際に期待どおりに機能しないことがわかりましたが、これはそれが書かれているはずの方法ではありません!

次のようなものを試してください:

(?=^.{8,15}$)(?=.*\d)(?=.*[A-Z])(?=.*[a-z])(?!.*\s).*$

(8から15まで、少なくとも1つの数字、少なくとも1つの大文字、少なくとも1つの小文字が含まれ、空白は含まれません。)

そして、これも理解しやすいと思います。

2
manojlds

長く、そしておそらく短くすることができます。特殊文字?"-_をサポートします。

\A(?=[-\?\"_a-zA-Z0-9]*?[A-Z])(?=[-\?\"_a-zA-Z0-9]*?[a-z])(?=[-\?\"_a-zA-Z0-9]*?[0-9])[-\?\"_a-zA-Z0-9]{8,15}\z
0
Ken White

ニコラス・キャリーに感謝します。私は最初に正規表現を使用するつもりでしたが、あなたが書いたことは私の心を変えました。この方法を維持する方がずっと簡単です。

//You can set these from your custom service methods
int minLen = 8;
int minDigit 2;
int minSpChar 2;

Boolean ErrorFlag = false;
//Check for password length
if (model.NewPassword.Length < minLen)
{
    ErrorFlag = true;
    ModelState.AddModelError("NewPassword", "Password must be at least " + minLen + " characters long.");
}

//Check for Digits and Special Characters
int digitCount = 0;
int splCharCount = 0;
foreach (char c in model.NewPassword)
{
    if (char.IsDigit(c)) digitCount++;
    if (Regex.IsMatch(c.ToString(), @"[!#$%&'()*+,-.:;<=>?@[\\\]{}^_`|~]")) splCharCount++;
}

if (digitCount < minDigit)
{
    ErrorFlag = true;
    ModelState.AddModelError("NewPassword", "Password must have at least " + minDigit + " digit(s).");
}
if (splCharCount < minSpChar)
{
    ErrorFlag = true;
    ModelState.AddModelError("NewPassword", "Password must have at least " + minSpChar + " special character(s).");
}

if (ErrorFlag)
    return View(model);
0
Max