Sécurité par Post-It

16

Comme vous le savez peut-être, les pirates sont partout et ils veulent tout pirater. On vous a demandé de définir des mots de passe qui empêcheront tout pirate informatique . Le problème est que votre patron a entendu dire que payer pour LOC est mauvais et qu'il vous paie 1800 $ - 0,03 $ * caractères insérés par mois pour vous faire écrire la chose la plus simple qui pourrait éventuellement fonctionner. Donc, vous devez utiliser un petit nombre de caractères (si tout va bien très petit), ou sinon oublier l'argent. De plus, votre patron ne se soucie pas de la langue que vous utiliserez.

Les exigences pour les bons mots de passe sont similaires à celles de l'article mentionné, sauf que les exigences basées sur le dictionnaire ont été supprimées pour éviter de faire dépendre la solution des fichiers externes, vous n'avez pas à vérifier les lettres en cours de réorganisation (difficile à comprendre ce que cela signifie réellement), la dernière règle est supprimée (Qu'est-ce que 3/4?) et ne vérifie pas les anciens mots de passe.

Les exigences exactes après avoir supprimé certaines exigences de l'article lié sont les suivantes:

  • avoir au moins 8 caractère (s)!
  • pas plus de 12 caractères!
  • avoir des caractères majuscules et minuscules!
  • ne pas avoir plus de 8 lettres majuscules!
  • ne pas avoir plus de 8 lettres minuscules!
  • avoir au moins 2 lettre (s)!
  • avoir une lettre directrice!
  • avoir au moins 1 chiffre (s)!
  • ne soyez pas votre nom d'utilisateur!
  • ne pas être votre nom d'utilisateur à l'envers!
  • ne contient pas votre nom d'utilisateur!
  • ne contient pas votre nom d'utilisateur à l'envers!
  • ne pas avoir plus d'une paire de caractères répétitifs!
  • pas 3 occurrences du même personnage!
  • ne contient pas de carats (^)
  • ne contient pas d'espace
  • ne contient pas =
  • pas conatain &
  • contient pas de #
  • contient pas de ,
  • pas conatain ;
  • contient pas de "
  • ne contient pas>
  • ne contient pas <
  • contient pas de [
  • ne contient pas |
  • contient pas de )

Toutes les fautes d'orthographe sur cette liste sont restées telles quelles.

$ ./checkpass
Username: John
Password: L!]E2m69
OK.

$ ./checkpass
Username: John
Password: JohnnhoJ12
Nope.

$ ./checkpass
Username: JOE.smith
Password: JOE!smith123
OK.

Le code le plus court gagne de l'argent (envoyé sous forme de fichier JPG). Il doit afficher les invites "Nom d'utilisateur:" et "Mot de passe:" et répondre avec un message exact.

Konrad Borowski
la source
1
Sympa, voir un défi de golf de code dans un article du Daily WTF, +1 ;-)
ChristopheD
1
Le premier exemple devrait échouer ("avoir des majuscules et des minuscules!"), N'est-ce pas?
Howard
@Howard: Cela signifie que les lettres majuscules et minuscules sont nécessaires dans le mot de passe. Remarquez l'absence de mot «pas».
Konrad Borowski
Il n'est pas très évident dans certaines polices que le l dans ce premier mot de passe est un ell minuscule et non le numéro un, donc je suis en train de le modifier pour le remplacer par une lettre minuscule non ambiguë.
Peter Taylor
@PeterTaylor Ah, merci. En effet, je l'ai lu comme 1(chiffre un) au lieu de ell.
Howard

Réponses:

8

Perl, 203 194 189 189 193 caractères

Voici mon point de vue Perl sur le problème:

print"Username: ";chop($u=<>);$n=reverse$u;print"Password: ";$_=<>;
say/^\pL.{7,11}$/*/\d/*/[A-Z]/*9>y/A-Z//&y/a-z//<9*/[a-z]/*
!/[" #,;->^&[|)]|(.)(.*\1.*\1|\1.*(.)\3)|\Q$u\E|\Q$n/?"OK.":"Nope."

Les expressions régulières vérifient, dans l'ordre, que le mot de passe:

  • commence par une lettre, a huit à douze caractères

  • contient un chiffre

  • contient une lettre majuscule

  • a huit lettres majuscules ou moins

  • a huit lettres minuscules ou moins

  • contient une lettre minuscule

  • ne contient aucun des signes de ponctuation interdits, trois occurrences d'un caractère, plus d'une occurrence d'un caractère doublé, le nom d'utilisateur ou le nom d'utilisateur inversé.

(Merci à Peter Taylor d'avoir signalé un bug dans la version 189 caractères.)

boite à pain
la source
Compris comment exécuter cela sur ideone avec use v5.10;et il échoue mon cas de test "sont des regex échappés correctement". Voir ideone.com/QKFnZ
Peter Taylor
@PeterTaylor: Je ne sais pas pour Ruby, mais en Perl, le correctif serait \Q$u\E|\Q$n(le dernier \Epeut être ignoré, si cette partie devait être déplacée à la fin).
Konrad Borowski
OTOH Je pense qu'un personnage peut être sauvé en fusionnant les répétitions comme (.)(.*\1.*\1|\1.*(.)\3)(non testé - je ne vais pas essayer de scripter une batterie de test complète avec ideone).
Peter Taylor
5

Ruby, 270 caractères

$><<"Username: ";u=gets.chop
$><<"Password: ";gets
puts ('^.{8,12}$+\p{Lower}+\p{Upper}+^(\p{Alpha}.*){2}+\d+(\p{Lower}.*){9}+(\p{Upper}.*){9}+(.)\1.*(.)\2+(.).*\1.*\1+[ ^=&#,;"<>\[|)]+'+u+?++u.reverse).split(?+).map{|r|/#{r}/=~$_??A:?B}*""=="AAAAABBBBBBB"?"OK.":"Nope."

Une implémentation ruby ​​s'appuie sur douze expressions régulières. Chaque expression est soit une correspondance positive (cinq premières) soit négative (sept dernières). Par restriction, le nom d'utilisateur ne peut contenir que des lettres ou des chiffres.

Correspondances d'expressions régulières positives:

  • /^.{8,12}$/: avoir au moins 8 caractère (s)!, ne pas dépasser 12 caractères!
  • /\p{Lower}/et /\p{Upper}/: avoir des majuscules et des minuscules!
  • /^(\p{Alpha}.*){2}/: avoir au moins 2 lettre (s) !, avoir une lettre principale!
  • /\d/: avoir au moins 1 chiffre (s)!

Correspondances d'expressions régulières négatives:

  • /(\p{Lower}.*){9}/: pas plus de 8 lettres minuscules!
  • /(\p{Upper}.*){9}/: pas plus de 8 lettres majuscules!
  • /(.)\1.*(.)\2/: ne pas avoir plus d'une paire de caractères répétitifs!
  • /(.).*\1.*\1/: pas 3 occurrences du même personnage!
  • /[ ^=&#,;"<>\[|)]/: ne contient pas de caret, espace, =, &, #, ,,;, ",>, <, [, |,)
  • /#{u}/: ne pas être votre nom d'utilisateur !, ne pas contenir votre nom d'utilisateur!
  • /#{u.reverse}/: ne pas être votre nom d'utilisateur à l'envers !, ne pas contenir votre nom d'utilisateur à l'envers!
Howard
la source
Cela n'échappe pas au nom d'utilisateur, donc un mot de passe parfaitement valide peut être rejeté. Cas de test sur ideone.com/bPpeo
Peter Taylor
@PeterTaylor C'est pourquoi j'ai noté la restriction des noms d'utilisateur dans ma réponse.
Howard
1

Python 3, 291 octets / caractères

from re import*
n,p=map(input,["Username: ","Password: "])
c,U,L=lambda x:len(split("[%s]"%x,p)),"A-Z","a-z"
print(["OK.","Nope."][any([8>len(p)>12,2>c(U)>9,2>c(L)>9,3>c(U+L),match(U+L,p),2>c("0-9"),n in p,n[::-1]in p,any(c(x)>3 for x in p),len(findall("(.)\\1",p))>1,c(' ^=&#,;"><[|)')>1])])

Plus joliment formaté et commenté:

# import all elements from the regular expression module
from re import *

# Get the two lines of user input (username `n`, password `p`):
n, p = map(input, ["Username: ","Password: "])

# Assign some internally useful shortcuts (uppercase letters `U`, lowercase letters `L`):
# `c(x)` counts the occurrences of pattern `x` in the password `p` plus 1
c, U, L = lambda x: len(split("[%s]" % x, p)), "A-Z", "a-z"

# Print the test result: `"OK."` if the `any(...)` function returned `False`, else `"Nope."`.
# The `any(...)` combines the result of all enclosed checks and returns `True` if at least
# one of the checks failed (returned `True`).
print(["OK.", "Nope."][any([                                # vvv--- CHECKS: ---vvv
                             8>len(p)>12,                   # password length 8-12
                             2>c(U)>9,                      # 1-8 uppercase letters
                             2>c(L)>9,                      # 1-8 lowercase letters
                             3>c(U+L),                      # at least 2 letters
                             match(U+L,p),                  # starts with a letter
                             2>c("0-9"),                    # at least 1 digit
                             n in p,                        # username is not (in) the pw.
                             n[::-1]in p,                   # reversed name not (in) the pw.
                             any(c(x)>3 for x in p),        # at most 3 same characters
                             len(findall("(.)\\1",p))>1,    # at most 1 pair (e.g. "AA")
                             c(' ^=&#,;"><[|)')>1])         # does not contain special char.
                           ])

Vous pouvez trouver cette solution sur ideone.com , mais la sortie semble un peu moche car elle ne montre pas l'entrée prédéfinie ou même des sauts de ligne. En outre, la combinaison nom d' utilisateur-mot de passe "JOE.smith"- "JOE!smith123"est actuellement saisie comme données d'entrée fixes.
J'ai cependant ajouté une ventilation de toutes les vérifications en tant que sortie de débogage.

Byte Commander
la source