Проверка пароля с помощью регулярного выражения

#regex #perl

#регулярное выражение #perl

Вопрос:

Я пишу регулярное выражение для проверки пароля.

Ниже приведены политики паролей, которые я хочу рассмотреть :

  1. Пароль может содержать только цифры, буквы и специальный символ.

  2. Минимальная длина пароля равна 10, а максимальная длина пароля равна 32.

  3. Один и тот же символ не должен появляться последовательно 10 или более раз.

  4. Первый символ не может быть специальным символом.

  5. Требуется как минимум 2 класса символов.(буквы, цифры или специальные символы)

  6. Разрешены специальные символы — !# ,-./:=@_

Регулярное выражение, которое будет удовлетворять первым 4 условиям, кроме 5-го пункта :

 ^(?!.*(.)1{7})[A-Za-z0-9][w!# ,./:=@-]{7,23}
  

Как я могу проверить все политики вместе в Java?

Комментарии:

1. Дайте отпор этим требованиям. Они создают пароли, которые людям трудно запомнить, но которые легко угадать компьютерам. В частности, удалите требуемые 2 класса и максимальную длину.

Ответ №1:

Лучший способ сделать это — не использовать регулярное выражение.

Подпрограмму с отдельными условиями намного проще читать и поддерживать:

 sub is_password_valid {
    my ($pw) = @_;
    $pw =~ m{[^a-zA-Z0-9!# ,-./:=@_]}
        and return 0;
    length($pw) >= 10 amp;amp; length($pw) <= 32
        or return 0;
    $pw =~ /(.)1{9}/s
        and return 0;
    $pw =~ /^[a-zA-Z0-9]/
        or return 0;
    ($pw =~ /[a-zA-Z]/   $pw =~ /[0-9]/   $pw =~ /[^a-zA-Z0-9]/) >= 2
        or return 0;
    return 1;
}
  

Или, в качестве альтернативы, поскольку это в основном всего лишь одно большое условие:

 sub is_password_valid {
    my ($pw) = @_;
    return
        $pw !~ m{[^a-zA-Z0-9!# ,-./:=@_]} amp;amp;
        length($pw) >= 10 amp;amp;
        length($pw) <= 32 amp;amp;
        $pw !~ /(.)1{9}/s amp;amp;
        $pw =~ /^[a-zA-Z0-9]/ amp;amp;
        ($pw =~ /[a-zA-Z]/   $pw =~ /[0-9]/   $pw =~ /[^a-zA-Z0-9]/) >= 2
    ;
}
  

Если это не игрушечный валидатор для домашнего задания, вам следует изменить свои требования. Не имеет смысла «проверять» пароли с помощью регулярного выражения.

Вместо этого вы должны требовать минимальную длину, иметь гораздо большую максимальную длину (возможно, 255 символов или около того) и не ограничивать используемый набор символов.

Если вы хотите защитить от слабых паролей, проверьте haveibeenpwned и дайте возможность взломщику паролей (например, hashcat) попробовать это.

Комментарии:

1. Я действительно не любитель использовать ... and/or return 0 вместо if (...) { return 0 } в этом контексте. (в противном случае я согласен, что использование инструкции для каждого требования лучше, чем пытаться уместить их все в одном регулярном выражении)

2. return 0 if ...; и return 0 unless ...; это более приятная, более идиоматическая нотация.

3. @Shawn я не согласен. Тест важнее, поэтому он на первом месте. return 0 по сравнению с этим довольно скучно. (Смотрите также: perlstyle )

4. Видите ли, я думаю, что в подобных случаях возврат ошибки является важной частью.

5. попытка взлома паролей вряд ли будет осуществима в пользовательском интерфейсе с набором пароля. вместо этого были бы хороши библиотеки для проверки энтропии / черного списка, например metacpan.org/pod/Data::Password::zxcvbn (порт perl библиотеки javascript zxcvbn; см. lowe.github.io/tryzxcvbn )

Ответ №2:

 print "Enter your password please: ";
$p=<STDIN>;chomp $p;

if ( $p =~ /(?!^[s!# ,-./:=@_])(?=^[w!# ,-./:=@]{10,32}$)(?=.*[A-Za-z])(?=.*[0-9])(?=.*[!# ,-./:=@_])(?!.*(.)1{9,}).{10,32}/ ) {print "Welcome"; f=1}
  

Комментарии:

1. пожалуйста, добавьте некоторые пояснения. ответы только на код не приветствуются в SO

Ответ №3:

Вместо того, чтобы создавать вложенный файл, возвращающий значение true для действительного пароля, противоположный вложенный файл может вместо этого возвращать ноль или более сообщений об ошибках.

Преимущество, конечно, в том, что сообщения об ошибках могут быть представлены пользователю, чтобы точно указать, какие правила нарушены, если таковые имеются.

 sub pwerr {
  local $_=pop;
  my $s='!# ,-./:=@_'; #allowed special chars
  grep $_,
  /^[a-zd$s] $/i        ? 0 : "Password must be just nums, letters and special chars $s",
  length()>=10           ? 0 : "Minimum length of the password is 10",
  length()<=32           ? 0 : "Maximum length of the password is 32",
  !/(.)1{9}/            ? 0 : "Same char 10 or more in a row",
  /^[a-zA-Z0-9]/         ? 0 : "First character can not be special character",
  1</[a-z]/i /d/ /[$s]/ ? 0 : "At least 2 char classes of letters, numbers or special $s";
}

use strict; use warnings; use Test::More tests => 7;
sub _test_string { join(" ",map{/^(S )/;$1}pwerr(shift()))||undef }
is(_test_string($$_[0]), $$_[1]) for map[split],grep/w/,split/n/,q(
1A!~                               Password Minimum
abc                                Minimum At
abcd12345-
abcd12345.
-abcd12345                         First
abcd4444444444                     Same
abcd12345.abcd12345.abcd12345.xyz  Maximum
);