it-swarm-pt.tech

Qual é a melhor maneira de verificar a força de uma senha?

Qual é a melhor maneira de garantir que uma senha fornecida pelo usuário seja uma senha forte em um formulário de registro ou alteração de senha?

Uma ideia que eu tive (em 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
42
Ed L

1: удалить часто используемые пароли
Проверьте введенные пароли ïî списку часто используемых паролей (см, Например, верхние 100 000 паролей в утечке списка паролей LinkedIn:.: http://www.adeptus-mechanicus.com/codex/linkhap/ combo_not .Zip , обязательно включите подстановки leetspeek : A @, E3, B8, S5 и т. д.
Удалите части пароля, попавшие в этот список, из введенной фразы, прежде чем переходить к части 2 ниже.

2: не навязывайте никаких правил пользователю

Олотое правило паролей в том, что чем дольше, тем лучше.
[. .____] Забудьте о принудительном использовании заглавных букв, цифр и символов, потому что (подавляющее большинство) пользователей будут: - Делать первую букву заглавной; - поставить номер 1 в конце; - Поставьте ! после этого, если требуется символ.

Вместо этого проверьте надежность пароля

Достойную отправную точку смотрите: http://www.passwordmeter.com/

Я предлагаю как минимум следующие правила:

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

Просто следовать passwordmeter недостаточно, потому что достаточно наивный алгоритм видитPassword1!как хорошо, тогда как он исключительно слабый. Обязательно игнорируйте начальные заглавные буквы при подсчете очков, атакже конечные цифры и символы (согласно последним 3 правилам).

Расчет энтропии Шеннона
См.: Самый быстрый способ вычисления энтропии em Python

3: не допускайте слишком слабых паролей
Вместо того, чтобы заставлять пользователя подчиняться саморазрушительным правилам, разрешите все, что даст достаточно высокий балл. Как высоко зависит от вашего варианта использования.

И самое главное
Когда вы принимаете пароль и сохраняете его в базе данных, не забудьте засолить и хешировать его! .

4
Johan

Dependendo do idioma, geralmente uso expressões regulares para verificar se tem:

  • Pelo menos uma letra maiúscula e uma minúscula
  • Pelo menos um numero
  • Pelo menos um caractere especial
  • Um comprimento de pelo menos seis caracteres

Você pode exigir todos os itens acima ou usar um tipo de script de medidor de força. Para meu medidor de força, se a senha tiver o tamanho certo, ela é avaliada da seguinte maneira:

  • Uma condição encontrada: senha fraca
  • Duas condições encontradas: senha média
  • Todas as condições encontradas: senha forte

Você pode ajustar os itens acima para atender às suas necessidades.

18
VirtuosiMedia

A abordagem orientada a objetos seria um conjunto de regras. Atribuir um peso a cada regra e iterar através deles. No código psuedo:

abstract class Rule {

    float weight;

    float calculateScore( string password );

}

Calculando a pontuação total:

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;

}

Um algoritmo de regra de exemplo, com base no número de classes de caracteres presentes:

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;

}
9
user9116

As duas métricas mais simples para verificar são:

  1. Comprimento. Eu diria 8 caracteres no mínimo.
  2. Número de classes de caracteres diferentes que a senha contém. Estas são geralmente, letras minúsculas, letras maiúsculas, números e pontuação e outros símbolos. Uma senha forte conterá caracteres de pelo menos três dessas classes; Se você forçar um número ou outro caractere não-alfabético, reduz significativamente a eficácia dos ataques de dicionário.
3
Dave Webb

O Cracklib é ótimo, e em pacotes mais novos existe um módulo Python disponível para ele. No entanto, em sistemas que ainda não o possuem, como o CentOS 5, escrevi um wrapper ctypes para o sistema cryptlib. Isso também funcionaria em um sistema no qual você não pode instalar o python-libcrypt. Ele faz requer python com ctypes disponíveis, então para o CentOS 5 você tem que instalar e usar o pacote python26.

Ele também tem a vantagem de poder usar o nome de usuário e verificar as senhas que o contêm ou são substancialmente similares, como a função "FascistGecos" do libcrypt, mas sem exigir que o usuário exista em/etc/passwd.

Minha biblioteca ctypescracklib está disponível no github

Alguns exemplos usam:

>>> 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'
2
Sean Reifschneider

depois de ler as outras respostas úteis, é com isso que eu vou:

-1 o mesmo que nome de usuário
+ 0 contém nome de usuário
+ 1 mais de 7 caracteres
+ 1 mais de 11 caracteres
+ 1 contém dígitos
+ 1 mistura de letras maiúsculas e minúsculas
+ 1 contém pontuação
+ 1 caractere não imprimível 

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

exemplo de uso:

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

provavelmente não é o mais eficiente, mas parece razoável. não tenho certeza se FascistCheck => 'muito parecido com o nome de usuário' vale .

'abc123ABC! @ £' = pontuação 6/6 se não for um superconjunto de nome de usuário

talvez isso devesse pontuar mais baixo.

2
siznax

Há o cracker aberto e gratuito John the Ripper , que é uma ótima maneira de verificar um banco de dados de senhas existente.

1
tante

Bem, isso é o que eu 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;
} 
1
varun

Eu escrevi um pequeno aplicativo Javascript. Dê uma olhada: Yet Another Password Meter . Você pode baixar a fonte e usá-la/modificá-la em GPL. Diverta-se!

0
ReneS

Eu não sei se alguém achará isso útil, mas eu realmente gostei da idéia de um conjunto de regras como sugerido por phear, então eu escrevi uma classe Python 2.6 (embora seja provavelmente compatível com 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__()

Espero que alguém ache isso útil!

Exemplo de uso:

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

ISENÇÃO DE RESPONSABILIDADE: Não testado em unidade

0
SapphireSun

Além da abordagem padrão de misturar alfa, numérico e símbolos, notei quando me registrei com MyOpenId na semana passada, o verificador de senha informa se sua senha é baseada em um dicionário Word, mesmo se você adicionar números ou substituir alfas com números semelhantes (usando zero em vez de 'o', '1' em vez de 'i', etc.).

Fiquei bastante impressionado.

0
Steve Morgan