#regex #perl
#регулярное выражение #perl
Вопрос:
Я пишу регулярное выражение для проверки пароля.
Ниже приведены политики паролей, которые я хочу рассмотреть :
-
Пароль может содержать только цифры, буквы и специальный символ.
-
Минимальная длина пароля равна 10, а максимальная длина пароля равна 32.
-
Один и тот же символ не должен появляться последовательно 10 или более раз.
-
Первый символ не может быть специальным символом.
-
Требуется как минимум 2 класса символов.(буквы, цифры или специальные символы)
-
Разрешены специальные символы —
!# ,-./:=@_
Регулярное выражение, которое будет удовлетворять первым 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
);