Je crée un script simple en Python qui évalue la force d'un mot de passe sur un système de score qui donne et prend des points selon qu'il contient ou non des lettres majuscules ou minuscules, des chiffres et des symboles pour l'école.
L'un des les exigences sont qu'il vérifie 3 lettres ou chiffres consécutifs de gauche à droite sur un clavier QWERTY britannique et enlève 5 points pour chaque instance. Par exemple, le mot de passe «qwer123» perdrait 15 points pour «qwe», «wer» et «123». Comment cela pourrait-il être accompli? Mon code actuel ci-dessous.
def check(): user_password_score=0 password_capitals=False password_lowers=False password_numbers=False password_symbols=False password_explanation_check=False ascii_codes=[] password_explanation=[] print("The only characters allowed in the passwords are upper and lower case letters, numbers and these symbols; !, $, %, ^, &, *, (, ), _, -, = and +.\n") user_password=str(input("Enter the password you would like to get checked: ")) print("") if len(user_password)>24 or len(user_password)<8: print("That password is not between 8 and 24 characters and so the Password Checker can't evaluate it.") menu() for i in user_password: ascii_code=ord(i) #print(ascii_code) ascii_codes.append(ascii_code) #print(ascii_codes) for i in range(len(ascii_codes)): if ascii_codes[i]>64 and ascii_codes[i]<90: password_capitals=True elif ascii_codes[i]>96 and ascii_codes[i]<123: password_lowers=True elif ascii_codes[i]>47 and ascii_codes[i]<58: password_numbers=True elif ascii_codes[i] in (33,36,37,94,38,42,40,41,45,95,61,43): password_symbols=True else: print("Your password contains characters that aren't allowed.\n") menu() if password_capitals==True: user_password_score+=5 if password_lowers==True: user_password_score+=5 if password_numbers==True: user_password_score+=5 if password_symbols==True: user_password_score+=5 if password_capitals==True and password_lowers==True and password_numbers==True and password_symbols==True: user_password_score+=10 if password_numbers==False and password_symbols==False: user_password_score-=5 if password_capitals==False and password_lowers==False and password_symbols==False: user_password_score-=5 if password_capitals==False and password_lowers==False and password_numbers==False: user_password_score-=5 #print(user_password_score) if user_password_score>20: print("Your password is strong.\n") else: print("That password is weak.\n") #don't forget you still need to add the thing that checks for 'qwe' and other stuff. menu()
4 Réponses :
Vous pouvez stocker des séquences interdites dans un ensemble de chaînes et décrémenter le score chaque fois que quelqu'un utilise cette séquence.
password = "qwert123" score = 42 # initial score sequences = { # all in lowercase because of the `lower()` in the loop "qwertyuiopasdfghjklzxcvbnm", "azertyuiopqsdfghjklmwxcvbn", "abcdefghijklmnopqrstuvwxyz", "01234567890" } match_length = 3 # length threshold for the sanction sequences.update({s[::-1] for s in sequences}) # do we allow reverse ? for c in range(len(password)-match_length+1): for seq in sequences: if password[c:c+match_length].lower() in seq: score-=5 print(f"'{password[c:c+match_length]}' => -5 !") break # Don't flag the same letters more than once print(score) # 22 (42-4*5)
Le moyen le plus simple est de forcer brutalement toutes les séquences possibles.
Créez 4 chaînes: "1234567890"
, "qwertyuiop"
, "asdfghjkl "
, " zxcvbnm "
et parcourez chacun avec 3 caractères du user_password
.
Vous pouvez initialiser cette liste au début de la fonction check
:
if(i<len(ascii_codes)-2): # since we will be checking for characters up to i+2 in our loop flag = False # initialize a flag to signal finding a match for s in sequences: # loop through each of the 4 keyboard sequences if(s.find(user_password[i: i+3].lower()) != -1): user_password_score -= 5 flag = True break if(flag): break
puis à l'intérieur de la boucle for i in range (len (ascii_codes))
ajouter:
sequences = ["1234567890", "qwertyuiop", "asdfghjkl", "zxcvbnm"]
notez également que la boucle se rompra après la première occurrence
@ BenoîtPilatte et c'est tout ce dont nous avons besoin, 3 personnages n'apparaîtront qu'une seule fois et dans une de ces séquences seulement!
@ BenoîtPilatte, c'est vrai, testez le code et vous verrez qu'il décrémente bien le score deux fois.
Ok, j'ai été confus par vos break
et votre boucle.
Je créerais une liste de séquences de touches adjacentes, comme d'autres mentionnées ci-dessus. Ensuite, je créerais une fonction de fenêtre coulissante pour générer toutes les séquences de longueur 3 et faire correspondre chacune d'elles avec le mot de passe: < pré> XXX
Si les expressions régulières sont autorisées, vous pouvez le faire en une seule ligne :
User password score: 42 Plain list of triplets: ['qwe', 'wer', 'ert', 'rty', 'tyu', 'yui', 'uio', 'iop', 'opa', 'pas', 'asd', 'sdf', 'dfg', 'fgh', 'ghj', 'hjk', 'jkl', 'klz', 'lzx', 'zxc', 'xcv', 'cvb', 'vbn', 'bnm', 'aze', 'zer', 'ert', 'rty', 'tyu', 'yui', 'uio', 'iop', 'opq', 'pqs', 'qsd', 'sdf', 'dfg', 'fgh', 'ghj', 'hjk', 'jkl', 'klm', 'lmw', 'mwx', 'wxc', 'xcv', 'cvb', 'vbn', 'abc', 'bcd', 'cde', 'def', 'efg', 'fgh', 'ghi', 'hij', 'ijk', 'jkl', 'klm', 'lmn', 'mno', 'nop', 'opq', 'pqr', 'qrs', 'rst', 'stu', 'tuv', 'uvw', 'vwx', 'wxy', 'xyz', '012', '123', '234', '345', '456', '567', '678', '789', '890'] Regex expression: (?=((qwe)|(wer)|(ert)|(rty)|(tyu)|(yui)|(uio)|(iop)|(opa)|(pas)|(asd)|(sdf)|(dfg)|(fgh)|(ghj)|(hjk)|(jkl)|(klz)|(lzx)|(zxc)|(xcv)|(cvb)|(vbn)|(bnm)|(aze)|(zer)|(ert)|(rty)|(tyu)|(yui)|(uio)|(iop)|(opq)|(pqs)|(qsd)|(sdf)|(dfg)|(fgh)|(ghj)|(hjk)|(jkl)|(klm)|(lmw)|(mwx)|(wxc)|(xcv)|(cvb)|(vbn)|(abc)|(bcd)|(cde)|(def)|(efg)|(fgh)|(ghi)|(hij)|(ijk)|(jkl)|(klm)|(lmn)|(mno)|(nop)|(opq)|(pqr)|(qrs)|(rst)|(stu)|(tuv)|(uvw)|(vwx)|(wxy)|(xyz)|(012)|(123)|(234)|(345)|(456)|(567)|(678)|(789)|(890))) Matches : ['qwe', 'wer', '123'] Penalty: -15 Final score: 27
Ce code est équivalent:
import re def build_pattern(sequences): all_triplets = [] triplets = [] for seq in sequences: for i in range(0, len(seq) - 2): triplets.append(seq[i:i+3]) all_triplets.append(triplets) triplets = [] expanded_triplets = [ x for y in all_triplets for x in y ] print("Plain list of triplets: " + str(expanded_triplets)) string_pattern = '|'.join( [ "({0})".format(x) for x in expanded_triplets ] ) lookahead_pattern = '(?=({0}))'.format(string_pattern) print("Regex expression: " + lookahead_pattern) return re.compile(lookahead_pattern) password = 'qwer123' user_password_score = 42 print("User password score: " + str(user_password_score)) sequences = ["qwertyuiopasdfghjklzxcvbnm", "azertyuiopqsdfghjklmwxcvbn", "abcdefghijklmnopqrstuvwxyz", "01234567890"] pattern = build_pattern(sequences) matches = [ match.group(1) for match in pattern.finditer(password) ] print("Matches : " + str(matches)) matches_count = len(matches) penalty = -5 * matches_count print("Penalty: " + str(penalty)) user_password_score += penalty print("Final score: " + str(user_password_score))
Et le code suivant est également équivalent (et, espérons-le, également lisible par l'homme). Nous l'imprimerons étape par étape pour mieux voir ce qu'il fait.
import re user_password_score = 42 pwd = 'qwer123' seqs = ["qwertyuiopasdfghjklzxcvbnm", "azertyuiopqsdfghjklmwxcvbn", "abcdefghijklmnopqrstuvwxyz", "01234567890"] pattern = re.compile('(?=({0}))'.format('|'.join(["({0})".format(w) for w in [x for y in [[s[i:i+3] for i in range(0,len(s)-2)] for s in seqs] for x in y]]))) penalty = -5 * len([match.group(1) for match in pattern.finditer(pwd) ]) user_password_score += penalty
Voici la sortie:
import re user_password_score = 42 pwd = 'qwer123' user_password_score += (lambda z : -5 * len([match.group(1) for match in re.compile('(?=({0}))'.format('|'.join(["({0})".format(w) for w in [x for y in [[s[i:i+3] for i in range(0,len(s)-2)] for s in ["qwertyuiopasdfghjklzxcvbnm", "azertyuiopqsdfghjklmwxcvbn", "abcdefghijklmnopqrstuvwxyz", "01234567890"]] for x in y]]))).finditer(z) ]))(pwd)
Dans la fonction build_pattern
, [x for y in all_triplets for x in y]
est une astuce pour développer une liste de listes en une liste simple. Un modèle d'expression régulière comme (lmw) | (mwx) | (wxc)
utilisé dans un finditer ()
indique que nous voulons trouver toutes les correspondances pour lmw, mwx et wxc. Et lorsque nous enveloppons ce modèle dans une anticipation ( (? = ())
), nous disons à re
qu'il devrait également inclure des correspondances qui se chevauchent sur le résultat. P >
Bienvenue dans Stack Overflow. Veuillez lire Comment demander et voir si vous pouvez rendre votre extrait de code un peu plus concis avec les parties essentielles .
Vous pouvez également publier votre code sur codereview.stackexchange.com . Si
x
est un booléen, vous pouvez remplacerif x == True
parif x
etif x == False code > avec
sinon x
.Vous pouvez également écrire
contains_numbers = any (char.isdigit () for char in password)
oucontains_uppercase = any (char.isupper () for char in password)
.