Как лучше всего проверить надежность пароля?
Вопрос
Как лучше всего гарантировать, что пароль, указанный пользователем, является надежным паролем в форме регистрации или смены пароля?
У меня была одна идея (на 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
Решение
1:Удалите часто используемые пароли
Сверьте введенные пароли со списком часто используемых паролей (см., например,100 000 самых популярных паролей в утекшем списке паролей LinkedIn: http://www.adeptus-mechanicus.com/codex/linkhap/combo_not.zip), обязательно включите замены: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
Просто следую парольметр недостаточно, потому что его наивный алгоритм видит Пароль1! как хороший, тогда как он исключительно слабый.Обязательно игнорируйте начальные заглавные буквы при подсчете очков, а также конечные цифры и символы (согласно последним трем правилам).
Вычисление энтропии Шеннона
Видеть: Самый быстрый способ вычисления энтропии в Python
3:Не допускайте использования слишком слабых паролей
Вместо того, чтобы заставлять пользователя подчиняться обреченным на провал правилам, разрешите все, что даст достаточно высокий балл.Насколько высоко зависит от вашего варианта использования.
И самое важное
Когда вы принимаете пароль и сохраняете его в базе данных, обязательно посолите и перемешайте!.
Другие советы
В зависимости от языка я обычно использую регулярные выражения, чтобы проверить, есть ли в нем:
- По крайней мере одна верхняя и одна строчная буква
- Хотя бы один номер
- Хотя бы один специальный символ
- Длина не менее шести символов
Вы можете потребовать все вышеперечисленное или использовать скрипт типа измерителя силы.Для моего измерителя силы, если пароль имеет правильную длину, он оценивается следующим образом:
- Выполнено одно условие:слабый пароль
- Выполнено два условия:средний пароль
- Все условия соблюдены:Надежный пароль
Вы можете настроить вышеизложенное в соответствии со своими потребностями.
Объектно-ориентированный подход представляет собой набор правил.Присвойте вес каждому правилу и выполните итерацию по ним.В псевдокоде:
abstract class Rule {
float weight;
float calculateScore( string password );
}
Подсчет общего балла:
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;
}
Пример алгоритма правила, основанный на количестве присутствующих классов символов:
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;
}
Два самых простых показателя для проверки:
- Длина.Я бы сказал, минимум 8 символов.
- Количество различных классов символов, содержащихся в пароле.Обычно это строчные и прописные буквы, цифры, знаки препинания и другие символы.Надежный пароль должен содержать символы как минимум трех из этих классов;если вы принудительно вводите число или другой неалфавитный символ, вы значительно снижаете эффективность атак по словарю.
Cracklib великолепен, и в новых пакетах для него доступен модуль Python.Однако в системах, в которых его еще нет, например в CentOS 5, я написал оболочку ctypes для системной библиотеки cryptlib.Это также будет работать в системе, в которой вы не можете установить python-libcrypt.Это делает требуется Python с доступными типами ctypes, поэтому для CentOS 5 вам необходимо установить и использовать пакет python26.
Он также имеет то преимущество, что он может использовать имя пользователя и проверять пароли, которые его содержат или по существу похожи, как функция libcrypt «FascistGecos», но без необходимости существования пользователя в /etc/passwd.
Мой Библиотека ctypescracklib доступна на github.
В некоторых примерах используется:
>>> 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'
прочитав другие полезные ответы, я собираюсь сделать следующее:
-1 то же, что и имя пользователя
+0 содержит имя пользователя
+1 более 7 символов
+1 более 11 символов
+1 содержит цифры
+1 сочетание нижнего и верхнего регистра
+1 содержит знаки препинания
+1 непечатаемый символ
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
пример использования:
import pwscore
score = pwscore(username,passwd)
if score < 3:
return "weak password (score="
+ str(score) + "/"
+ str(pwscore.max_score)
+ "), try again."
вероятно, не самый эффективный, но кажется разумным.Не уверен, что Fachistcheck => «Слишком похоже на имя пользователя» того стоит.
'abc123ABC!@£' = оценка 6/6, если не является расширенным набором имен пользователей.
возможно, это должно иметь более низкую оценку.
Там открыто и бесплатно Джон Потрошитель взломщик паролей, который является отличным способом проверить существующую базу данных паролей.
Ну вот что я использую:
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;
}
В дополнение к стандартному подходу смешивания букв, цифр и символов, когда я регистрировался в MyOpenId на прошлой неделе, я заметил, что средство проверки пароля сообщает вам, основан ли ваш пароль на словарном слове, даже если вы добавляете цифры или заменяете буквы похожими цифрами. (используя ноль вместо «о», «1» вместо «i» и т. д.).
Я был очень впечатлен.
Я написал небольшое приложение на Javascript.Взглянем: Еще один счетчик паролей.Вы можете скачать исходный код и использовать/изменять его под лицензией GPL.Веселиться!
Я не знаю, покажется ли кому-нибудь это полезным, но мне очень понравилась идея набора правил, предложенная pher, поэтому я пошел и написал класс правил Python 2.6 (хотя он, вероятно, совместим с 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__()
Я надеюсь, что кто-то найдет это полезным!
Пример использования:
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
ОТКАЗ ОТ ОТВЕТСТВЕННОСТИ:Не проверено
Если у вас есть время, запустите взломщик паролей.
Средства проверки надежности паролей, и если у вас есть время + ресурсы (это оправдано, только если вы проверяете более нескольких паролей), используйте Rainbow Tables.
С помощью серии проверок, чтобы убедиться, что он соответствует минимальным критериям:
- длина не менее 8 символов
- содержит хотя бы один небуквенно-цифровой символ
- не соответствует или не содержит имя пользователя/адрес электронной почты/и т. д.
- и т. д.
Вот плагин jQuery, который сообщает о надежности пароля (сам не пробовал):http://phiras.wordpress.com/2007/04/08/password-strength-meter-a-jquery-plugin/
И то же самое портировано на PHP:http://www.alixaxel.com/wordpress/2007/06/09/php-password-strength-algorithm/
Каков наилучший способ гарантировать, что пароль, указанный пользователем, является надежным паролем в форме регистрации или смены пароля?
Не оценивайте сложность и силу, пользователи найдут способ обмануть вашу систему или настолько разочаруются, что уйдут.Это приведет только к ситуациям так.Просто потребуйте определенной длины и чтобы утекшие пароли не использовались.Бонусные очки:убедитесь, что все, что вы реализуете, позволяет использовать менеджеры паролей и/или 2FA.