Domanda

Qual è il modo migliore per garantire che la password fornita dall'utente sia una password complessa in un modulo di registrazione o di modifica della password?

Un'idea che ho avuto (in Python)

def validate_password(passwd):
    conditions_met = 0
    conditions_total = 3
    if len(passwd) >= 6: 
        if passwd.lower() != passwd: conditions_met += 1
        if len([x for x in passwd if x.isdigit()]) > 0: conditions_met += 1
        if len([x for x in passwd if not x.isalnum()]) > 0: conditions_met += 1
    result = False
    print conditions_met
    if conditions_met >= 2: result = True
    return result
È stato utile?

Soluzione

1:Elimina le password usate spesso
Confronta le password immesse con un elenco di password utilizzate spesso (vedi ad es.le prime 100.000 password nell'elenco delle password trapelate da LinkedIn: http://www.adeptus-mechanicus.com/codex/linkhap/combo_not.zip), assicurati di includere sostituzioni leetspeek:A@, E3, B8, S5, ecc.
Rimuovi le parti della password che rientrano in questo elenco dalla frase inserita, prima di passare alla parte 2 di seguito.

2:Non imporre alcuna regola all'utente

La regola d'oro delle password è che più lunghe sono, meglio è.
Dimentica l'uso forzato di maiuscole, numeri e simboli perché (la stragrande maggioranza degli) utenti:- Rendi la prima lettera maiuscola;- Metti il ​​numero 1 alla fine;- Metti a ! successivamente se è richiesto un simbolo.

Controlla invece la sicurezza della password

Per un buon punto di partenza vedere: http://www.passwordmeter.com/

Suggerisco come minimo le seguenti regole:

Additions (better passwords)
-----------------------------
- Number of Characters              Flat       +(n*4)   
- Uppercase Letters                 Cond/Incr  +((len-n)*2)     
- Lowercase Letters                 Cond/Incr  +((len-n)*2)     
- Numbers                           Cond       +(n*4)   
- Symbols                           Flat       +(n*6)
- Middle Numbers or Symbols         Flat       +(n*2)   
- Shannon Entropy                   Complex    *EntropyScore

Deductions (worse passwords)
----------------------------- 
- Letters Only                      Flat       -n   
- Numbers Only                      Flat       -(n*16)  
- Repeat Chars (Case Insensitive)   Complex    -    
- Consecutive Uppercase Letters     Flat       -(n*2)   
- Consecutive Lowercase Letters     Flat       -(n*2)   
- Consecutive Numbers               Flat       -(n*2)   
- Sequential Letters (3+)           Flat       -(n*3)   
- Sequential Numbers (3+)           Flat       -(n*3)   
- Sequential Symbols (3+)           Flat       -(n*3)
- Repeated words                    Complex    -       
- Only 1st char is uppercase        Flat       -n
- Last (non symbol) char is number  Flat       -n
- Only last char is symbol          Flat       -n

Sto solo seguendo passwordmetro non è sufficiente, perché sicuramente il suo ingenuo algoritmo vede Parola d'ordine1! altrettanto buono, mentre è eccezionalmente debole.Assicurati di ignorare le lettere maiuscole iniziali quando conteggi, nonché i numeri e i simboli finali (come previsto dalle ultime 3 regole).

Calcolo dell'entropia di Shannon
Vedere: Il modo più veloce per calcolare l'entropia in Python

3:Non consentire password troppo deboli
Piuttosto che costringere l'utente a piegarsi a regole autodistruttive, consenti tutto ciò che darà un punteggio sufficientemente alto.Quanto in alto dipende dal caso d'uso.

E, soprattutto
Quando accetti la password e la memorizzi in un database, assicurati di salarlo e tritarlo!.

Altri suggerimenti

A seconda della lingua, di solito utilizzo le espressioni regolari per verificare se ha:

  • Almeno una lettera maiuscola e una lettera minuscola
  • Almeno un numero
  • Almeno un carattere speciale
  • Una lunghezza di almeno sei caratteri

Puoi richiedere tutto quanto sopra o utilizzare uno script di tipo misuratore di forza.Per il mio misuratore di forza, se la password ha la lunghezza giusta, viene valutata come segue:

  • Una condizione soddisfatta:Password Debole
  • Sono soddisfatte due condizioni:password media
  • Tutte le condizioni sono soddisfatte:password sicura

Puoi modificare quanto sopra per soddisfare le tue esigenze.

L'approccio orientato agli oggetti sarebbe un insieme di regole.Assegna un peso a ciascuna regola ed esegui l'iterazione.In pseudo-codice:

abstract class Rule {

    float weight;

    float calculateScore( string password );

}

Calcolo del punteggio totale:

float getPasswordStrength( string password ) {     

    float totalWeight = 0.0f;
    float totalScore  = 0.0f;

    foreach ( rule in rules ) {

       totalWeight += weight;
       totalScore  += rule.calculateScore( password ) * rule.weight;

    }

    return (totalScore / totalWeight) / rules.count;

}

Un esempio di algoritmo di regole, basato sul numero di classi di caratteri presenti:

float calculateScore( string password ) {

    float score = 0.0f;

    // NUMBER_CLASS is a constant char array { '0', '1', '2', ... }
    if ( password.contains( NUMBER_CLASS ) )
        score += 1.0f;

    if ( password.contains( UPPERCASE_CLASS ) )
        score += 1.0f;

    if ( password.contains( LOWERCASE_CLASS ) )
        score += 1.0f;

    // Sub rule as private method
    if ( containsPunctuation( password ) )
        score += 1.0f;

    return score / 4.0f;

}

I due parametri più semplici da verificare sono:

  1. Lunghezza.Direi 8 caratteri come minimo.
  2. Numero di classi di caratteri diverse contenute nella password.Di solito si tratta di lettere minuscole, lettere maiuscole, numeri, segni di punteggiatura e altri simboli.Una password complessa conterrà caratteri di almeno tre di queste classi;se forzi un numero o un altro carattere non alfabetico riduci notevolmente l'efficacia degli attacchi del dizionario.

Cracklib è fantastico e nei pacchetti più recenti è disponibile un modulo Python per questo.Tuttavia, sui sistemi che non lo hanno ancora, come CentOS 5, ho scritto un wrapper ctypes per il sistema cryptlib.Funzionerebbe anche su un sistema su cui non è possibile installare python-libcrypt.Esso fa richiede Python con ctype disponibili, quindi per CentOS 5 devi installare e utilizzare il pacchetto python26.

Ha anche il vantaggio di poter prendere il nome utente e verificare la presenza di password che lo contengono o che sono sostanzialmente simili, come la funzione "FascistGecos" di libcrypt ma senza richiedere all'utente di esistere in /etc/passwd.

Mio La libreria ctypescracklib è disponibile su github

Alcuni esempi utilizzano:

>>> FascistCheck('jafo1234', 'jafo')
'it is based on your username'
>>> FascistCheck('myofaj123', 'jafo')
'it is based on your username'
>>> FascistCheck('jxayfoxo', 'jafo')
'it is too similar to your username'
>>> FascistCheck('cretse')
'it is based on a dictionary word'

dopo aver letto le altre risposte utili, questo è ciò che intendo fare:

-1 uguale al nome utente
+0 contiene il nome utente
+1 più di 7 caratteri
+1 più di 11 caratteri
+1 contiene cifre
+1 mix di minuscole e maiuscole
+1 contiene la punteggiatura
+1 carattere non stampabile

pwscore.py:

import re
import string
max_score = 6
def score(username,passwd):
    if passwd == username:
        return -1
    if username in passwd:
        return 0
    score = 0
    if len(passwd) > 7:
        score+=1
    if len(passwd) > 11:
        score+=1
    if re.search('\d+',passwd):
        score+=1
    if re.search('[a-z]',passwd) and re.search('[A-Z]',passwd):
        score+=1
    if len([x for x in passwd if x in string.punctuation]) > 0:
        score+=1
    if len([x for x in passwd if x not in string.printable]) > 0:
        score+=1
    return score

utilizzo di esempio:

import pwscore
    score = pwscore(username,passwd)
    if score < 3:
        return "weak password (score=" 
             + str(score) + "/"
             + str(pwscore.max_score)
             + "), try again."

probabilmente non il più efficiente, ma sembra ragionevole.Non sono sicuro che fascistCheck => 'Troppo simile al nome utente' ne valga la pena.

'abc123ABC!@£' = punteggio 6/6 se non è un superset di nome utente

forse dovrebbe ottenere un punteggio più basso.

C'è l'aperto e il gratuito Giovanni lo Squartatore cracker di password che è un ottimo modo per controllare un database di password esistente.

Bene, questo è quello che uso:

   var getStrength = function (passwd) {
    intScore = 0;
    intScore = (intScore + passwd.length);
    if (passwd.match(/[a-z]/)) {
        intScore = (intScore + 1);
    }
    if (passwd.match(/[A-Z]/)) {
        intScore = (intScore + 5);
    }
    if (passwd.match(/\d+/)) {
        intScore = (intScore + 5);
    }
    if (passwd.match(/(\d.*\d)/)) {
        intScore = (intScore + 5);
    }
    if (passwd.match(/[!,@#$%^&*?_~]/)) {
        intScore = (intScore + 5);
    }
    if (passwd.match(/([!,@#$%^&*?_~].*[!,@#$%^&*?_~])/)) {
        intScore = (intScore + 5);
    }
    if (passwd.match(/[a-z]/) && passwd.match(/[A-Z]/)) {
        intScore = (intScore + 2);
    }
    if (passwd.match(/\d/) && passwd.match(/\D/)) {
        intScore = (intScore + 2);
    }
    if (passwd.match(/[a-z]/) && passwd.match(/[A-Z]/) && passwd.match(/\d/) && passwd.match(/[!,@#$%^&*?_~]/)) {
        intScore = (intScore + 2);
    }
    return intScore;
} 

Oltre all'approccio standard che prevede la combinazione di caratteri alfanumerici e simboli, ho notato quando mi sono registrato su MyOpenId la settimana scorsa, il controllo password ti dice se la tua password è basata su una parola del dizionario, anche se aggiungi numeri o sostituisci alfa con numeri simili (usando zero invece di 'o', '1' invece di 'i', ecc.).

Sono rimasto molto colpito.

Ho scritto una piccola applicazione Javascript.Guarda: Ancora un altro misuratore di password.Puoi scaricare il sorgente e usarlo/modificarlo sotto GPL.Divertiti!

Non so se qualcuno lo troverà utile, ma mi è piaciuta molto l'idea di un set di regole suggerito da phear, quindi sono andato e ho scritto una classe di regole Python 2.6 (anche se probabilmente è compatibile con 2.5):

import re

class SecurityException(Exception):
    pass

class Rule:
    """Creates a rule to evaluate against a string.
    Rules can be regex patterns or a boolean returning function.
    Whether a rule is inclusive or exclusive is decided by the sign
    of the weight. Positive weights are inclusive, negative weights are
    exclusive. 


    Call score() to return either 0 or the weight if the rule 
    is fufilled. 

    Raises a SecurityException if a required rule is violated.
    """

    def __init__(self,rule,weight=1,required=False,name=u"The Unnamed Rule"):
        try:
            getattr(rule,"__call__")
        except AttributeError:
            self.rule = re.compile(rule) # If a regex, compile
        else:
            self.rule = rule  # Otherwise it's a function and it should be scored using it

        if weight == 0:
            return ValueError(u"Weights can not be 0")

        self.weight = weight
        self.required = required
        self.name = name

    def exclusive(self):
        return self.weight < 0
    def inclusive(self):
        return self.weight >= 0
    exclusive = property(exclusive)
    inclusive = property(inclusive)

    def _score_regex(self,password):
        match = self.rule.search(password)
        if match is None:
            if self.exclusive: # didn't match an exclusive rule
                return self.weight
            elif self.inclusive and self.required: # didn't match on a required inclusive rule
                raise SecurityException(u"Violation of Rule: %s by input \"%s\"" % (self.name.title(), password))
            elif self.inclusive and not self.required:
                return 0
        else:
            if self.inclusive:
                return self.weight
            elif self.exclusive and self.required:
                raise SecurityException(u"Violation of Rule: %s by input \"%s\"" % (self.name,password))
            elif self.exclusive and not self.required:
                return 0

        return 0

    def score(self,password):
        try:
            getattr(self.rule,"__call__")
        except AttributeError:
            return self._score_regex(password)
        else:
            return self.rule(password) * self.weight

    def __unicode__(self):
        return u"%s (%i)" % (self.name.title(), self.weight)

    def __str__(self):
        return self.__unicode__()

Spero che qualcuno lo trovi utile!

Esempio di utilizzo:

rules = [ Rule("^foobar",weight=20,required=True,name=u"The Fubared Rule"), ]
try:
    score = 0
    for rule in rules:
        score += rule.score()
except SecurityException e:
    print e 
else:
    print score

DISCLAIMER:Non testato sull'unità

Se hai tempo, esegui un cracker di password contro di esso.

I controllori della sicurezza della password e se hai tempo e risorse (è giustificato solo se stai controllando più di poche password) usa Rainbow Tables.

Con una serie di controlli per garantire che soddisfi i criteri minimi:

  • lungo almeno 8 caratteri
  • contiene almeno un simbolo non alfanumerico
  • non corrisponde o non contiene nome utente/e-mail/ecc.
  • eccetera

Ecco un plug-in jQuery che segnala la sicurezza della password (non l'ho provato personalmente):http://phiras.wordpress.com/2007/04/08/password-strength-meter-a-jquery-plugin/

E la stessa cosa portata su PHP:http://www.alixaxel.com/wordpress/2007/06/09/php-password-strength-algorithm/

Qual è il modo migliore per garantire che la password fornita dall'utente sia una password complessa in un modulo di registrazione o di modifica della password?

Non valutare la complessità e/o la forza, gli utenti troveranno un modo per ingannare il tuo sistema o saranno così frustrati che se ne andranno.Questo ti porterà solo situazioni come questo.Richiedi solo una certa lunghezza e che le password trapelate non vengano utilizzate.Punti bonus:assicurati che qualunque cosa implementi consenta l'uso di gestori di password e/o 2FA.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top