Bezpieczeństwo przez Post-It

16

Jak zapewne wiesz, hakerzy są wszędzie i chcą zhakować wszystko. Zostaliśmy poproszeni o określenie wymagań dotyczących hasła, które powstrzymają każdego hakera . Problem polega na tym, że twój szef słyszał, że płacenie za LOC jest złe i płaci ci 1800 $ - 0,03 $ * znaków wstawianych miesięcznie, abyś napisał najprostszą rzecz, która prawdopodobnie mogłaby zadziałać. Musisz więc użyć małej liczby znaków (mam nadzieję, że bardzo mała) lub w inny sposób zapomnieć o gotówce. Ponadto szefowi nie zależy na tym, jakiego języka będziesz używać.

Wymagania dotyczące dobrych haseł są podobne do tych we wspomnianym artykule, z wyjątkiem wymagań opartych na słowniku, aby uniknąć uzależnienia rozwiązania od plików zewnętrznych, nie musisz sprawdzać, czy litery są uporządkowane (Trudno zrozumieć, co to właściwie oznacza), ostatnia reguła została usunięta (Co to jest 3/4?) i nie sprawdza starych haseł.

Dokładne wymagania po usunięciu niektórych wymagań z powiązanego artykułu to:

  • mieć co najmniej 8 znaków!
  • nie może być dłuższy niż 12 znaków!
  • mają wielkie i małe litery!
  • mieć nie więcej niż 8 wielkich liter!
  • mieć nie więcej niż 8 małych liter!
  • mieć co najmniej 2 litery!
  • mieć wiodący list!
  • mieć co najmniej 1 cyfrę (y)!
  • nie być twoją nazwą użytkownika!
  • nie być twoją nazwą użytkownika wstecz!
  • nie zawiera twojej nazwy użytkownika!
  • nie zawierają odwrotnie nazwy użytkownika!
  • mieć nie więcej niż 1 parę powtarzających się postaci!
  • nie mieć 3 wystąpień tej samej postaci!
  • nie zawiera karat (^)
  • nie zawiera spacji
  • nie zawiera =
  • nie conatain &
  • nie zawiera #
  • nie zawiera ,
  • nie conatain ;
  • nie zawiera "
  • nie zawierają>
  • nie zawiera <
  • nie zawiera [
  • nie zawierają |
  • nie zawiera )

Wszystkie błędy pisowni na tej liście pozostały bez zmian.

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

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

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

Najkrótszy kod wygrywa pieniądze (wysyłane jako plik JPG). Musi wyświetlać monity „Nazwa użytkownika” i „Hasło:” oraz odpowiadać dokładną wiadomością.

Konrad Borowski
źródło
1
Fajnie, widzę wyzwanie golfowego kodu w artykule Daily WTF, +1 ;-)
ChristopheD
1
Pierwszy przykład powinien zawieść („mieć wielkie i małe litery!”), Prawda?
Howard
@Howard: Oznacza to, że w haśle potrzebne są zarówno wielkie, jak i małe litery. Zauważ brak słowa „nie”.
Konrad Borowski
W niektórych czcionkach nie jest bardzo oczywiste, że litera w tym pierwszym haśle jest małą literą, a nie cyfrą, więc edytuję, aby zastąpić ją jednoznaczną małą literą.
Peter Taylor,
@PeterTaylor Ah, dziękuję. Rzeczywiście czytam to jako 1(cyfrę pierwszą) zamiast ell.
Howard

Odpowiedzi:

8

Perl, 203 194 189 193 znaków

Oto mój Perl podchodzi do problemu:

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."

Wyrażenia regularne sprawdzają, aby hasło:

  • zaczyna się na literę, ma osiem do dwunastu znaków

  • zawiera cyfrę

  • zawiera wielką literę

  • ma osiem lub mniej wielkich liter

  • ma osiem lub mniej małych liter

  • zawiera małą literę

  • nie zawiera żadnych zabronionych znaków interpunkcyjnych, trzech wystąpień dowolnego znaku, więcej niż jednego wystąpienia znaku podwójnego, nazwy użytkownika lub odwróconej nazwy użytkownika.

(Podziękowania dla Petera Taylora za wskazanie błędu w wersji 189 znaków).

chlebak
źródło
Zrozumiałem, jak uruchomić to na ideone, use v5.10;a to się nie udaje mój testowy przypadek „are regexes escaped poprawnie”. Zobacz ideone.com/QKFnZ
Peter Taylor
@PeterTaylor: Nie wiem o Ruby, ale w Perlu byłaby to poprawka \Q$u\E|\Q$n(ostatnia \Emoże zostać pominięta, jeśli ta część zostanie przeniesiona na koniec).
Konrad Borowski
OTOH Myślę, że jedną postać można uratować, łącząc powtórzenia jako (.)(.*\1.*\1|\1.*(.)\3)(nie testowane - nie będę próbował skryptować pełnej baterii testowej za pomocą ideonu).
Peter Taylor
5

Ruby, 270 znaków

$><<"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."

Implementacja ruby ​​opiera się na dwunastu wyrażeniach regularnych. Każde wyrażenie jest dopasowaniem dodatnim (pierwsze pięć) lub ujemnym (ostatnie siedem). Jako ograniczenie nazwa użytkownika może zawierać tylko litery lub cyfry.

Pozytywne dopasowania wyrażeń regularnych:

  • /^.{8,12}$/: mieć co najmniej 8 znaków !, nie może być dłuższy niż 12 znaków!
  • /\p{Lower}/i /\p{Upper}/: mają wielkie i małe litery!
  • /^(\p{Alpha}.*){2}/: mieć co najmniej 2 litery (litery) !, mieć literę wiodącą!
  • /\d/: mieć co najmniej 1 cyfrę (y)!

Negatywne dopasowania wyrażeń regularnych:

  • /(\p{Lower}.*){9}/: nie więcej niż 8 małych liter!
  • /(\p{Upper}.*){9}/: mieć nie więcej niż 8 wielkich liter!
  • /(.)\1.*(.)\2/: mieć nie więcej niż 1 parę powtarzających się postaci!
  • /(.).*\1.*\1/: nie ma 3 wystąpień tej samej postaci!
  • /[ ^=&#,;"<>\[|)]/: nie zawiera znaku karetki, spacji, =, &, #, ,,;, ",>, <, [, |,)
  • /#{u}/: nie może być Twoją nazwą użytkownika!, nie zawiera Twojej nazwy użytkownika!
  • /#{u.reverse}/: nie bądź odwrotnie nazwą użytkownika !, nie odwracaj nazwy użytkownika!
Howard
źródło
Nie zmienia to nazwy użytkownika, więc idealnie prawidłowe hasło może zostać odrzucone. Przypadek testowy na ideone.com/bPpeo
Peter Taylor
@PeterTaylor Dlatego w odpowiedzi zauważyłem ograniczenie nazw użytkowników.
Howard
1

Python 3, 291 bajtów / znaków

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])])

Bardziej ładnie sformatowane i skomentowane:

# 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.
                           ])

Możesz znaleźć to rozwiązanie na ideone.com , ale dane wyjściowe wyglądają nieco brzydko, ponieważ nie pokazują tam predefiniowanych danych wejściowych ani nawet podziałów linii. Ponadto kombinacja nazwy użytkownika i hasła "JOE.smith"- "JOE!smith123"jest obecnie wprowadzana jako stałe dane wejściowe.
Dodałem jednak zestawienie wszystkich kontroli jako danych wyjściowych debugowania.

Bajt Dowódca
źródło