web-dev-qa-db-ja.com

パスワードの強度を確認する最良の方法は何ですか?

ユーザーが入力したパスワードが、登録フォームまたはパスワード変更フォームで強力なパスワードであることを確認する最良の方法は何ですか?

私が持っていた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
43
Ed L

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:弱すぎるパスワードは許可しない
ユーザーに自己破滅的なルールに曲げるよう強制するのではなく、十分に高いスコアを与えるものをすべて許可します。どのくらい高いかは、ユースケースによって異なります。

そして最も重要なこと
パスワードを受け入れてデータベースに保存するとき、 必ずソルトしてハッシュしてください

言語に応じて、私は通常、正規表現を使用して、次のことを確認します。

  • 少なくとも1つの大文字と1つの小文字
  • 少なくとも1つの番号
  • 少なくとも1つの特殊文字
  • 6文字以上の長さ

上記のすべてを要求するか、強度計タイプのスクリプトを使用できます。私の強度メーターでは、パスワードが適切な長さである場合、次のように評価されます。

  • 1つの条件が満たされた:弱いパスワード
  • 2つの条件を満たす:中程度のパスワード
  • すべての条件を満たす:強力なパスワード

上記をニーズに合わせて調整できます。

17
VirtuosiMedia

オブジェクト指向のアプローチは一連のルールになります。各ルールに重みを割り当て、それらを反復処理します。擬似コード:

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;

}
10
user9116

チェックする最も単純な2つのメトリックは次のとおりです。

  1. 長さ。私は最低でも8文字と言っています。
  2. パスワードに含まれるさまざまな文字クラスの数。これらは通常、小文字、大文字、数字、句読点、その他の記号です。強力なパスワードには、これらのクラスのうち少なくとも3つのクラスの文字が含まれます。数字やアルファベット以外の文字を強制すると、辞書攻撃の効果が大幅に低下します。
3
Dave Webb

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

他の役立つ答えを読んだ後、これは私がやっていることです:

-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

多分それはより低いスコアになるはずです。

2
siznax

オープンで無料の John the Ripper パスワードクラッカーがあり、これは既存のパスワードデータベースをチェックするのに最適な方法です。

1
tante

まあこれは私が使うものです:

   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

小さなJavascriptアプリケーションを作成しました。見てみましょう: Yet Another Password Meter 。ソースをダウンロードして、GPLで使用/変更できます。楽しんで!

0
ReneS

誰かがこれが役立つと思うかどうかはわかりませんが、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

免責事項:単体テストされていません

0
SapphireSun

アルファベット、数字、記号を混合する標準的なアプローチに加えて、先週MyOpenIdに登録したときに、パスワードチェッカーが、パスワードを辞書の単語に基づいているかどうかを通知します。 (「o」の代わりにゼロ、「i」の代わりに「1」などを使用します)。

とても感動しました。

0
Steve Morgan