Czy naprawdę chcesz zaufać środkom bezpieczeństwa swojego hasła w całym Internecie?
Borealid
12
@Borealid: publikowanie zasad haseł zazwyczaj nie powinno znacząco wpływać na Twoje bezpieczeństwo. Jeśli tak, oznacza to, że Twoje zasady są złe („Tylko passwordi hello123są prawidłowe hasła!”).
Joachim Sauer
3
@Joachim Sauer: Nie to miałem na myśli. Chodziło mi o to, że plakat prawdopodobnie po prostu zaufa dowolnemu wyrażeniu regularnemu, które otrzyma. Nie taki dobry pomysł.
Borealid
3
Właściwie to wyrażenie regularne będzie w kodzie serwisowym, będę testować przypadki różnic, a nie ślepo mu ufać :)
Ajay Kelkar
9
Złożone zasady dotyczące haseł zwykle nie prowadzą do bezpieczniejszych haseł, ważna jest tylko minimalna długość. Ludzie nie pamiętają ton silnych haseł, a takie zasady mogą kolidować z dobrymi schematami haseł. Ludzie mogą być bardzo pomysłowi omijając takie zasady, np. Używając słabych haseł, takich jak „Hasło-2014”. Często kończy się to ze słabszymi hasłami zamiast silniejszych.
martinstoeckli
Odpowiedzi:
427
Możesz przeprowadzić te sprawdzenia, używając twierdzeń pozytywnych przewidujących:
^ Start anchor
(?=.*[A-Z].*[A-Z]) Ensure string has two uppercase letters.
(?=.*[!@#$&*]) Ensure string has one special case letter.
(?=.*[0-9].*[0-9]) Ensure string has two digits.
(?=.*[a-z].*[a-z].*[a-z]) Ensure string has three lowercase letters.
.{8} Ensure string is of length 8.
$ End anchor.
Dla każdego, kto chce długość co najmniej nwymienić .{8}z.{n,}
NullUserException
14
+1 za pełne wyjaśnienie. Moje zasady dotyczące hasła są inne, ale na podstawie Twojej odpowiedzi mogę dostosować wyrażenie regularne.
Morvael
14
Dziękuję za opisanie, co się dzieje w wyrażeniu regularnym. To świetny przykład do nauki dla tych z nas, którzy nigdy nie radzili sobie ze składnią.
4
Doceniam również wyjaśnienie wyrażenia regularnego. Zbyt wiele razy używam złożonych wyrażeń regularnych, które znalazłem, nie rozumiejąc, co się dzieje.
Nicholas Smith
4
Świetny wzór, zastanawiam się, dlaczego nie użyć kwantyfikatorów? Co najmniej 1 specjalny, 1 cyfra, 1 znak specjalny, 8 znaków: ^ (? =. * ([AZ]) {1,}) (? =. * [! @ # $ & *] {1,}) ( ? =. * [0-9] {1,}) (? =. * [Az] {1,}). {8,100} $
RockOnGom
11
Możesz użyć dodatnich wyprzedzeń o zerowej długości, aby osobno określić każde z ograniczeń:
Odpowiedzi podane powyżej są doskonałe, ale sugeruję użycie kilku mniejszych wyrażeń regularnych zamiast dużego.
Dzielenie długiego wyrażenia regularnego ma kilka zalet:
łatwość pisania i czytania
łatwość debugowania
łatwość dodawania / usuwania części wyrażenia regularnego
Generalnie takie podejście zapewnia łatwość utrzymania kodu .
Powiedziawszy to, udostępniam fragment kodu, który piszę w języku Swift jako przykład:
structRegExp{/**
Check password complexity
- parameter password: password to test
- parameter length: password min length
- parameter patternsToEscape: patterns that password must not contains
- parameter caseSensitivty: specify if password must conforms case sensitivity or not
- parameter numericDigits: specify if password must conforms contains numeric digits or not
- returns: boolean that describes if password is valid or not
*/static func checkPasswordComplexity(password password:String, length:Int, patternsToEscape:[String], caseSensitivty:Bool, numericDigits:Bool)->Bool{if(password.length < length){returnfalse}if caseSensitivty {let hasUpperCase =RegExp.matchesForRegexInText("[A-Z]", text: password).count >0if!hasUpperCase {returnfalse}let hasLowerCase =RegExp.matchesForRegexInText("[a-z]", text: password).count >0if!hasLowerCase {returnfalse}}if numericDigits {let hasNumbers =RegExp.matchesForRegexInText("\\d", text: password).count >0if!hasNumbers {returnfalse}}if patternsToEscape.count >0{let passwordLowerCase = password.lowercaseString
for pattern in patternsToEscape {let hasMatchesWithPattern =RegExp.matchesForRegexInText(pattern, text: passwordLowerCase).count >0if hasMatchesWithPattern {returnfalse}}}returntrue}static func matchesForRegexInText(regex:String, text:String)->[String]{do{let regex =tryNSRegularExpression(pattern: regex, options:[])let nsString = text asNSStringlet results = regex.matchesInString(text,
options:[], range:NSMakeRange(0, nsString.length))return results.map { nsString.substringWithRange($0.range)}}catchlet error asNSError{print("invalid regex: \(error.localizedDescription)")return[]}}}
Ponadto, używając złożonego wyrażenia regularnego, takiego jak powyżej, bardzo łatwo jest otworzyć się na katastroficzne cofanie ( regular-expressions.info/catastrophic.html ). Może to pozostać niezauważone, aż pewnego dnia serwer zawiesza się ze 100% procesorem, ponieważ użytkownik użył „dziwnego” hasła. Przykład: ^ ([a-z0-9] +) {8,} $ (czy widzisz błąd?)
aKzenT
5
Sugerowałbym dodanie
(?!.*pass|.*word|.*1234|.*qwer|.*asdf) exclude common passwords
Rozwiązanie codaddict działa dobrze, ale to jest nieco bardziej wydajne: (składnia Pythona)
password = re.compile(r"""(?#!py password Rev:20160831_2100)
# Validate password: 2 upper, 1 special, 2 digit, 1 lower, 8 chars.
^ # Anchor to start of string.
(?=(?:[^A-Z]*[A-Z]){2}) # At least two uppercase.
(?=[^!@#$&*]*[!@#$&*]) # At least one "special".
(?=(?:[^0-9]*[0-9]){2}) # At least two digit.
.{8,} # Password length is 8 or more.
$ # Anchor to end of string.
""", re.VERBOSE)
Klasy znaków zanegowanych pochłaniają wszystko do pożądanego znaku w jednym kroku, nie wymagając żadnego cofania. (Rozwiązanie z gwiazdą kropkową działa dobrze, ale wymaga pewnego cofania). Oczywiście w przypadku krótkich ciągów znaków docelowych, takich jak hasła, ta poprawa wydajności będzie nieistotna.
Czy mógłbyś sprawdzić, czy to prawda? Mam wątpliwości z powodu otwierającego nawias okrągły w pierwszej linii między potrójnym cudzysłowem a znakiem zapytania. Widzę, że komentarz Pythona (skrót) jest później. Nie widzę korespondenta zamykającego okrągłego nawiasu blisko końca kotwicy (znak dolara). Powinienem wspomnieć, że nie jestem profy regex.
lospejos
@lospejos - # nie jest początkiem zwykłego komentarza w jednej linii. Ten skrót jest częścią grupy komentarzy, która zaczyna się od (?#a kończy się a ). W tym wyrażeniu regularnym nie ma niezrównoważonych par.
ridgerunner
1
import re
RegexLength=re.compile(r'^\S{8,}$')RegexDigit=re.compile(r'\d')RegexLower=re.compile(r'[a-z]')RegexUpper=re.compile(r'[A-Z]')defIsStrongPW(password):ifRegexLength.search(password)==NoneorRegexDigit.search(password)==NoneorRegexUpper.search(password)==NoneorRegexLower.search(password)==None:returnFalseelse:returnTruewhileTrue:
userpw=input("please input your passord to check: \n")if userpw =="exit":breakelse:print(IsStrongPW(userpw))
Powinieneś także rozważyć zmianę niektórych zasad, aby:
Dodaj więcej znaków specjalnych, np.%, ^, (,), -, _, + i kropka. Dodaję wszystkie pominięte znaki specjalne nad znakami liczbowymi na klawiaturach w USA. Ucieknij z tych, których używa regex.
Wprowadź hasło co najmniej 8 znaków. Nie tylko statyczna liczba 8.
Dzięki powyższym ulepszeniom oraz dla większej elastyczności i czytelności zmodyfikowałbym wyrażenie regularne do.
(?=.*RULE){MIN_OCCURANCES,}Each rule block is shown by(){}.The rule and number of occurrences can then be easily specified and tested separately, before getting combined
Szczegółowe wyjaśnienie
^ start anchor
(?=.*[a-z]){3,} lowercase letters.{3,} indicates that you want 3ofthisgroup(?=.*[A-Z]){2,} uppercase letters.{2,} indicates that you want 2ofthisgroup(?=.*[0-9]){2,} numbers.{2,} indicates that you want 2ofthisgroup(?=.*[!@#$%^&*()--__+.]){1,} all the special characters in the [] fields.The ones used by regex are escaped byusing the \ or the character itself.{1,}is redundant, but good practice,incase you change that to more than 1in the future.Also keeps all the groups consistent
{8,} indicates that you want 8or more
$ end anchor
I na koniec, do celów testowych, jest tutaj robulink z powyższym wyrażeniem regularnym
Dzięki @AFract. Używam go w moim kodzie. Podoba mi się czytelność i powtarzalność, gdy trzeba wrócić i zmienić to w przyszłości, np. W przypadku zmiany polityki haseł :)
dlaczego nie return preg_match("/^(?=(?:[^A-Z]*[A-Z]){2})(?=(?:[^0-9]*[0-9]){2}).{8,}$/", 'CaSu4Li8')?
aloisdg przenosi się do codidact.com
0
Inne rozwiązanie:
import re
passwordRegex = re.compile(r'''(
^(?=.*[A-Z].*[A-Z]) # at least two capital letters
(?=.*[!@#$&*]) # at least one of these special c-er
(?=.*[0-9].*[0-9]) # at least two numeric digits
(?=.*[a-z].*[a-z].*[a-z]) # at least three lower case letters
.{8,} # at least 8 total digits
$
)''', re.VERBOSE)def userInputPasswordCheck():print('Enter a potential password:')whileTrue:
m = input()
mo = passwordRegex.search(m)if(not mo):print('''
Your password should have at least one special charachter,
two digits, two uppercase and three lowercase charachter. Length: 8+ ch-ers.
Enter another password:''')else:print('Password is strong')return
userInputPasswordCheck()
Hasło musi spełniać co najmniej 3 z poniższych 4 zasad złożoności,
[co najmniej 1 duża litera (AZ) co najmniej 1 mała litera (az) co najmniej 1 cyfra (0-9) co najmniej 1 znak specjalny - nie zapomnij również traktować spacji jako znaków specjalnych]
co najmniej 10 znaków
maksymalnie 128 znaków
nie więcej niż 2 identyczne znaki w rzędzie (np. 111 niedozwolonych)
Powyższe wyrażenie regularne ma minimalną długość 8. Możesz je zmienić z {8,} na { any_number ,}
Modyfikacja zasad?
powiedzmy, że chcesz mieć minimum x znaków małych liter, y znaków wielkich liter, z znaków liczb, Całkowita minimalna długość w . Następnie spróbuj poniżej wyrażenia regularnego
Twoje wyrażenie regularne pasuje 12345678, czy na pewno jest to silne hasło? Przed wysłaniem wypróbuj swoje wyrażenie regularne.
Toto
To lepiej, ale nie odpowiada na pytanie, chcą 1) długości 8 znaków. 2) 2 wielkie litery. 3) 1 znak specjalny (! @ # $ & *). 4) 2 cyfry (0-9). 5) 3 małe litery.
Toto
@Toto Czy możesz teraz podzielić się swoimi przemyśleniami?
Juned Khatri
Twoje wyrażenie regularne nie bierze pod uwagę, że 2 obowiązkowe wielkie litery mogą być oddzielone innymi znakami, ta sama uwaga dla małych liter i cyfr. Prawidłowa odpowiedź to ta, która została zaakceptowana.
password
ihello123
są prawidłowe hasła!”).Odpowiedzi:
Możesz przeprowadzić te sprawdzenia, używając twierdzeń pozytywnych przewidujących:
Link rubularny
Wyjaśnienie:
źródło
n
wymienić.{8}
z.{n,}
Możesz użyć dodatnich wyprzedzeń o zerowej długości, aby osobno określić każde z ograniczeń:
Jeśli regex silnik nie obsługuje
\p
zapis i czystego ASCII wystarczy, można wymienić\p{Lu}
z[A-Z]
i\p{Ll}
z[a-z]
.źródło
Odpowiedzi podane powyżej są doskonałe, ale sugeruję użycie kilku mniejszych wyrażeń regularnych zamiast dużego.
Dzielenie długiego wyrażenia regularnego ma kilka zalet:
Generalnie takie podejście zapewnia łatwość utrzymania kodu .
Powiedziawszy to, udostępniam fragment kodu, który piszę w języku Swift jako przykład:
źródło
Sugerowałbym dodanie
źródło
Rozwiązanie codaddict działa dobrze, ale to jest nieco bardziej wydajne: (składnia Pythona)
Klasy znaków zanegowanych pochłaniają wszystko do pożądanego znaku w jednym kroku, nie wymagając żadnego cofania. (Rozwiązanie z gwiazdą kropkową działa dobrze, ale wymaga pewnego cofania). Oczywiście w przypadku krótkich ciągów znaków docelowych, takich jak hasła, ta poprawa wydajności będzie nieistotna.
źródło
(?#
a kończy się a)
. W tym wyrażeniu regularnym nie ma niezrównoważonych par.źródło
Rozwiązanie @ codaddict będzie działać.
Powinieneś także rozważyć zmianę niektórych zasad, aby:
Dzięki powyższym ulepszeniom oraz dla większej elastyczności i czytelności zmodyfikowałbym wyrażenie regularne do.
Podstawowe wyjaśnienie
Szczegółowe wyjaśnienie
I na koniec, do celów testowych, jest tutaj robulink z powyższym wyrażeniem regularnym
źródło
W przypadku PHP to działa dobrze!
w tym przypadku wynik jest prawdziwy
Podziękowania dla @ridgerunner
źródło
return preg_match("/^(?=(?:[^A-Z]*[A-Z]){2})(?=(?:[^0-9]*[0-9]){2}).{8,}$/", 'CaSu4Li8')
?Inne rozwiązanie:
źródło
Hasło musi spełniać co najmniej 3 z poniższych 4 zasad złożoności,
[co najmniej 1 duża litera (AZ) co najmniej 1 mała litera (az) co najmniej 1 cyfra (0-9) co najmniej 1 znak specjalny - nie zapomnij również traktować spacji jako znaków specjalnych]
co najmniej 10 znaków
maksymalnie 128 znaków
nie więcej niż 2 identyczne znaki w rzędzie (np. 111 niedozwolonych)
'^ (?!. (.) \ 1 {2}) ((? =. [Az]) (? =. [AZ]) (? =. [0-9]) | (? =. [Az] ) (? =. [AZ]) (? =. [^ A-zA-Z0-9]) | (? =. [AZ]) (? =. [0-9]) (? =. [^ A -zA-Z0-9]) | (? =. [az]) (? =. [0-9]) (? =. * [^ a-zA-Z0-9])). {10,127} $ '
(?!. * (.) \ 1 {2})
(? =. [az]) (? =. [AZ]) (? =. * [0-9])
(? =. [az]) (? =. [AZ]) (? =. * [^ a-zA-Z0-9])
(? =. [AZ]) (? =. [0-9]) (? =. * [^ A-zA-Z0-9])
(? =. [az]) (? =. [0-9]) (? =. * [^ a-zA-Z0-9])
. {10.127}
źródło
Wszystkie powyższe wyrażenia regularne niestety nie działały dla mnie. Podstawowe zasady silnego hasła to
Więc najlepszy byłby Regex
Powyższe wyrażenie regularne ma minimalną długość 8. Możesz je zmienić z {8,} na { any_number ,}
Modyfikacja zasad?
powiedzmy, że chcesz mieć minimum x znaków małych liter, y znaków wielkich liter, z znaków liczb, Całkowita minimalna długość w . Następnie spróbuj poniżej wyrażenia regularnego
Uwaga: zmień x , y , z , w w wyrażeniu regularnym
Edycja: zaktualizowana odpowiedź wyrażenia regularnego
Edit2: Dodano modyfikację
źródło
12345678
, czy na pewno jest to silne hasło? Przed wysłaniem wypróbuj swoje wyrażenie regularne.