ユーザーが入力したパスワードが、登録フォームまたはパスワード変更フォームで強力なパスワードであることを確認する最良の方法は何ですか?
私が持っていた1つのアイデア(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:頻繁に使用するパスワードを排除します
入力したパスワードをよく使用するパスワードのリストと照合します(たとえば、漏えいしたLinkedInパスワードリストの上位100.000個のパスワードを参照してください: 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つのルールに従って)スコアリングおよび後続の数字と記号の場合は、最初の大文字を無視してください。
シャノンエントロピーの計算
参照: 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;
}
チェックする最も単純な2つのメトリックは次のとおりです。
Cracklibは素晴らしいものであり、新しいパッケージではPythonモジュールが利用可能です。しかし、CentOS 5など、まだそれを持っていないシステムでは、ctypesラッパーを作成しましたシステムcryptlibの場合。これは、python-libcryptをインストールできないシステムでも機能します。doesrequire 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."
おそらく最も効率的ではありませんが、妥当なようです。 FascistCheck =>「ユーザー名に類似しています」の価値があるかどうかは不明です。
'abc123ABC!@£' =ユーザー名のスーパーセットでない場合はスコア6/6
多分それはより低いスコアになるはずです。
オープンで無料の John the Ripper パスワードクラッカーがあり、これは既存のパスワードデータベースをチェックするのに最適な方法です。
まあこれは私が使うものです:
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;
}
小さなJavascriptアプリケーションを作成しました。見てみましょう: Yet Another Password Meter 。ソースをダウンロードして、GPLで使用/変更できます。楽しんで!
誰かがこれが役立つと思うかどうかはわかりませんが、phearによって提案されたルールセットのアイデアが本当に好きだったので、ルールを書き、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
免責事項:単体テストされていません
アルファベット、数字、記号を混合する標準的なアプローチに加えて、先週MyOpenIdに登録したときに、パスワードチェッカーが、パスワードを辞書の単語に基づいているかどうかを通知します。 (「o」の代わりにゼロ、「i」の代わりに「1」などを使用します)。
とても感動しました。