プロジェクトでvaadin、spring、jpaを使用しています。パスワードの強度を確認してユーザーに通知する必要があり、純粋な Java で実行したいと考えています。
それを行うための最良の方法をお勧めできますか?特別なライブラリを使用するか、パスワードに少なくとも1つの数字が含まれているかどうかなどを正規表現で確認する方がよいでしょうか。どう思いますか?
これと良いライブラリまたはチュートリアルへのリンクがあれば、私に送ってください。
一般に、誰かのパスワードの強度は、パスワードの推測可能性に依存します。より複雑なパスワードは推測されにくくなります。辞書攻撃やブルート フォース アルゴリズムがパスワードを推測する可能性に関連付けることで、複雑さを見積もることができます。パスワードが一般的なものではないことが確認されたら、ブルート フォースを使用してパスワードを推測するのにかかる時間から、パスワードの複雑さを見積もることができます。この意味で、同様のランダム パスワードが持つバイナリ ビット エントロピーの数を測定できます。これは推測可能性の概算ですが、あるコメンターが指摘しているように、複雑さを測定することは困難です。私が受講したあるセキュリティ クラスでは、インストラクターは少なくとも 40 ビットのエントロピーを目指すべきだと提案しましたが、60 ビットは安全と見なされます (ランダムに選択されたパスワードとパスワードを区別できないと仮定すると)。そう、パスワード メーターの仕事は、同等のランダム パスワードのエントロピーを推測することです。明らかに、ここには多くの落とし穴があり、確立されたライブラリを使用すると時間を大幅に節約できます。
1 文字あたりのエントロピーは log10(number_possible_characters)/log10(2) なので、エントロピーを次のように計算できますpwd.length() * Math.log10(numPossibleCharacters)/Math.log10(2)
-- 26 文字で、1 文字あたり約 4.7 ビットのエントロピーです。
純粋に科学的な方法でエントロピーを測定することは、推測可能性の有効な推定であるとは限りません。パスワード「abc123」は、(人間ではなくコンピューターにとって)「j3s9fn」と同じように見えるかもしれませんが、人間は最初のパスワードを簡単に確認できます。 2番目よりも推測される可能性がはるかに高くなります。厳密に言えば、エントロピーは真のランダム性の尺度です。人間がランダムではないことはわかっていますが、代わりにエントロピーを測定するほどランダムに近い可能性があります。アルゴリズムが、人間が生み出すランダム性/創造性/推測不可能性の種類を測定することを願っています. したがって、これは技術的な問題と人間の行動の問題の両方です。
私の記憶が正しければ、英語の散文 (1 ページに書かれた単語) には 1 文字あたり約 1.5 ビットのエントロピーしかないと言われたことがあります。意味不明な小文字をランダムに入力するよりも、英語の単語を入力するだけで「強力」になるように長いパスワードを使用してください。率直に言って、記号/数字/大文字を要求するパスワード システムは馬鹿げていると思います。YMMV。
ユーザーが入力した文字ごとに、ユーザーが選択できた、または選択する可能性が高い文字数を推定することにより、エントロピーの測定を開始する必要があります。
可能な文字数は、ユーザーが使用しているように見える文字セット、または使用を許可したnumPossibleCharacters
文字セットに基づいています。たとえば、ユーザーが入力した場合、可能な 26 文字 (1 文字あたり 4.7) からのみ選択していると想定できます。ただし、入力する場合は、52 (小文字と大文字) (1 文字あたり 5.7) から選択したと想定します。数字を使用する場合は、別の 10 文字を追加します (明らかな数字のみを選択していると思われる場合を除きます)。abc
aBc
また、後付けで数字を追加するユーザーは、パスワードの先頭または末尾に数字を追加する傾向があります。そのため、文字セットを変更する回数も、パスワードの強度の良い尺度となる可能性があります。たとえば、「word908」は「w39or7d」よりも明らかに安全性が低くなります。これを行うと、複雑さの単純な見積もりから外れます。
この複雑さのより緩い定義を使用すると、パスワードがあらゆる種類の攻撃によって推測される可能性を測定することははるかに難しくなりますが、最も推測しやすく、可能性が高いパターン。各文字の追加された複雑さ (エントロピー?) は、直前の文字と同じ文字セットにあるかどうか、前の文字から連続しているかどうか、または明らかなパターン (「123」や"abc")。
ある文字セットから別の文字セット (小文字から大文字、または数字から記号) への各切り替えは、それ自体が偶然の出来事であると言うかもしれません。小文字、大文字、数字、common_symbols、uncommon_symbols の 5 つの文字セットを定義するとします。これらのセットの使用中の数を検出します (たとえば、ユーザーが「123abc」と入力した場合charSetsUsed
は 2 です)。次に、文字列内の文字を 1 つずつループします。ユーザーが文字セットを変更するたびに、entropy += log(charSetsUsed)/log(2)
. 次に、各文字についても追加しentropy += log(charsInThisCharSet)/log(2)
ます。[編集: これは実際にはエントロピーではないため、推定複雑度として読む必要があるかもしれません]
本当に技術的になりたい場合は、文字セットの変更数を測定できます。パスワードの長さが 10 文字だとしましょう。1 ~ 9 回のセット変更が可能で、これは 10 個のオプションです。次に、スロットの組み合わせとして配布されていると言います。したがって、これを行います。
log(numChanges)/log(2) + log(combination(totalSlots, usedSlots))/log(2).
ユーザーが aoq35esm42 と入力したとします。あるキャラクター セットから別のキャラクター セットに切り替えた場所が 3 か所あります。これは 10 文字のパスワードであるため、セットの変更には 9 つの可能な位置があり (位置が 2 つの文字のいずれかの間にある場合)、それらの順序は関係ありません (したがって、組み合わせ/二項係数/n は r を選択します):
log(numChanges)/log(2) + log(combination(9, 3))/log(2).
log(3 )/log(2) + log( 84 )/log(2).
1.5849625 + 6.3
7.97727992
したがって、ほぼ 8 ビットのエントロピーがあることがわかります。これは、基本的に「文字セットを変更するために選択できたすべての場所と時間のうち、約 8 ビットのランダムなビットまたは 2^8 の可能性があり、ここで実行できた可能性がある」ことを示しています。次に、サブセットに基づいて各文字のエントロピーを計算し、各変更で使用するサブセットを選択すると、おそらく次のようにエントロピーに追加されます (計算を間違えた場合は訂正してください)。
組み合わせは、Apache Commons の MathUtils.binomialCoefficientDouble() 関数を使用して計算されます。
また、パスワードに辞書の単語が含まれている場合、そのパスワードは脆弱であると見なされます。したがって、辞書をスキャンできる場合、これらの文字は、1 文字あたり 1.5 ビットのエントロピーを持つ英語の散文として測定する必要があると想定 (推測) できます。ただし、パスワードをデータベースクエリ (ログに記録される可能性がある場所) にさらしたくないので、最善の策は、英語の単語があるかどうかを推測することです (幸運)。母音を含む 3 ~ 5 個の大文字と小文字のアルファベットが英語の単語です。または、最も一般的な英語の音節の辞書を作成することもできます。これは、メモリに格納するのがはるかに簡単な場合があります。または、あきらめて、ユーザーがパスワードを覚えやすくするためにとにかくシステムをゲームするだろうと想定することもできます。
それでも、正確であると判断した場合は、英単語のメモリ内データベースを安全なメモリに格納できます。
これらすべてが、おそらくまだ不完全なかなり複雑なアルゴリズムになります。おそらく、比較的簡単な計算を行うか、他の誰かが既に作成したライブラリを使用する必要があります。
「安全な保管」
パスワードのセキュリティを計算する方法は、まったく別の問題を実際に説明しているわけではありません。ネットワークを通過するとき、またはクライアントのメモリ内でパスワードを安全に保つことです。私はここの専門家ではありませんが、用心して宿題をするのに十分なほど読んだことがあります. 少なくとも https を使用し、ブラウザのネイティブ パスワード入力フィールドの使用を強く検討します。これは、独自のテクノロジーを展開することを避け、代わりにライブラリを使用するもう 1 つの理由です (ただし、管理できる以上の宿題を彼らが行っていることがわかる限り。調べてみました)。さらに、パスワードを平文で保存してはならず、一方向の暗号化/ハッシュを使用してください。パスワードをソルトし、安全なハッシュ アルゴリズムを使用してハッシュします (MD5 ではありません。おそらく SHA2 を好みますか?)。再ハッシュと再ソルトを複数回行う可能性があります (辞書攻撃のコストを増やすため)。通常、パスワードの強度を測定しない場合でも、この種のことを処理するライブラリがあります。C# や .NET には、意図的にソルティング、ハッシュ、反復を目的としたライブラリがあることを知っています。ここでは触れていない問題が他にもあると思いますが、パスワードの強度はセキュリティ チェーンの 1 つのリンクに過ぎないことを覚えておいてください。
Pure Java では、VT Passwordを使用してパスワードの強度を確認できます。Maven Central から入手可能:
<dependencies>
<dependency>
<groupId>edu.vt.middleware</groupId>
<artifactId>vt-password</artifactId>
<version>3.1.1</version>
</dependency>
<dependencies>