パスワードの強度を正確に把握できる効果的なアルゴリズムを探していました。
さまざまな Web サイトでさまざまなパスワード強度評価を得ているため、いくつかの異なる Web サイトではいくつかの異なるアルゴリズムが使用されていることがわかりました。
パスワードの強度を正確に把握できる効果的なアルゴリズムを探していました。
さまざまな Web サイトでさまざまなパスワード強度評価を得ているため、いくつかの異なる Web サイトではいくつかの異なるアルゴリズムが使用されていることがわかりました。
これは、PHP/MySQL でパスワードを操作するためのベスト プラクティスの一般的なブレイン ダンプに成長しました。ここに提示されたアイデアは、一般的に私自身のものではありませんが、これまでに見つけたものの中で最高のものです.
ログインの失敗回数を制限するだけで、ほとんどの攻撃を排除できます。
比較的脆弱なパスワードを許可しますが、ユーザーごとのログイン失敗回数を保存し、それを超えた場合はキャプチャまたはメールによるパスワード確認を要求します。最大失敗数を 5 に設定しました。
ログインの失敗をユーザーに提示することは、攻撃者に情報を提供しないように慎重に検討する必要があります。存在しないユーザーが原因でログインに失敗した場合は、パスワードが正しくないためにログインに失敗した場合と同じメッセージが返されます。別のメッセージを提供すると、攻撃者は有効なユーザー ログインを特定できます。
また、有効なパスワードを使用したログインが多すぎて失敗した場合と、ログインが多すぎてパスワードが正しくない場合に失敗した場合でも、まったく同じメッセージを返すようにしてください。別のメッセージを提供すると、攻撃者は有効なユーザー パスワードを特定できます。パスワードのリセットを強制された場合、かなりの数のユーザーが単純にパスワードを元に戻します。
残念ながら、IP アドレスごとに許可されるログイン数を制限することは実用的ではありません。AOL などのいくつかのプロバイダーとほとんどの企業は、Web 要求をプロキシします。この制限を課すと、これらのユーザーを効果的に排除できます。
本質的に脆弱なパスワードから辞書の単語を差し引いたものをチェックすることは、いくつかの単純な JavaScript を使用した実用的なクライアント側です。
送信後、辞書の単語とパスワードを含むユーザー名をチェックし、その逆もサーバー側で行います。非常に優れた辞書は簡単にダウンロードでき、それらに対するテストは簡単です。ここでの注意点の 1 つは、辞書の単語をテストするには、パスワードを含むデータベースに対してクエリを送信する必要があることです。私がこれを回避した方法は、単純な暗号化を使用して事前に辞書を暗号化し、最後に SALT を配置してから、暗号化されたパスワードをテストすることでした。理想的ではありませんが、プレーン テキストよりも優れており、物理マシンとサブネット上のユーザーに対してのみ送信されます。
彼らが選んだパスワードに満足したら、最初に PHP で暗号化してから保存します。次のパスワード暗号化関数も私の考えではありませんが、多くの問題を解決します。PHP 内で暗号化すると、共有サーバー上のユーザーが暗号化されていないパスワードを傍受するのを防ぐことができます。変更されないユーザーごとに何かを追加し (これは私のサイトのユーザー名であるため、電子メールを使用します)、ハッシュ (SALT はサイトごとに変更する短い定数文字列です) を追加すると、攻撃に対する耐性が向上します。SALT はパスワード内にあり、パスワードは任意の長さにできるため、レインボー テーブルでこれを攻撃することはほとんど不可能になります。代わりに、人々は自分の電子メールを変更できず、全員のパスワードを無効にしない限り SALT を変更できないことも意味します。
編集:ここで独自の関数をロールする代わりにPhPassを使用するか、ユーザー ログインを完全に忘れて代わりにOpenIDを使用することをお勧めします。
function password_crypt($email,$toHash) {
$password = str_split($toHash,(strlen($toHash)/2)+1);
return hash('sha256', $email.$password[0].SALT.$password[1]);
}
私の Jqueryish クライアント側のパスワード メーター。ターゲットは div である必要があります。幅は 0 から 100 の間で変化し、背景色はスクリプトに示されているクラスに基づいて変化します。繰り返しますが、私が見つけた他のものからほとんど盗まれました:
$.updatePasswordMeter = function(password,username,target) {
$.updatePasswordMeter._checkRepetition = function(pLen,str) {
res = ""
for ( i=0; i<str.length ; i++ ) {
repeated=true;
for (j=0;j < pLen && (j+i+pLen) < str.length;j++)
repeated=repeated && (str.charAt(j+i)==str.charAt(j+i+pLen));
if (j<pLen) repeated=false;
if (repeated) {
i+=pLen-1;
repeated=false;
}
else {
res+=str.charAt(i);
};
};
return res;
};
var score = 0;
var r_class = 'weak-password';
//password < 4
if (password.length < 4 || password.toLowerCase()==username.toLowerCase()) {
target.width(score + '%').removeClass("weak-password okay-password good-password strong-password"
).addClass(r_class);
return true;
}
//password length
score += password.length * 4;
score += ( $.updatePasswordMeter._checkRepetition(1,password).length - password.length ) * 1;
score += ( $.updatePasswordMeter._checkRepetition(2,password).length - password.length ) * 1;
score += ( $.updatePasswordMeter._checkRepetition(3,password).length - password.length ) * 1;
score += ( $.updatePasswordMeter._checkRepetition(4,password).length - password.length ) * 1;
//password has 3 numbers
if (password.match(/(.*[0-9].*[0-9].*[0-9])/)) score += 5;
//password has 2 symbols
if (password.match(/(.*[!,@,#,$,%,^,&,*,?,_,~].*[!,@,#,$,%,^,&,*,?,_,~])/)) score += 5;
//password has Upper and Lower chars
if (password.match(/([a-z].*[A-Z])|([A-Z].*[a-z])/)) score += 10;
//password has number and chars
if (password.match(/([a-zA-Z])/) && password.match(/([0-9])/)) score += 15;
//
//password has number and symbol
if (password.match(/([!,@,#,$,%,^,&,*,?,_,~])/) && password.match(/([0-9])/)) score += 15;
//password has char and symbol
if (password.match(/([!,@,#,$,%,^,&,*,?,_,~])/) && password.match(/([a-zA-Z])/)) score += 15;
//password is just a nubers or chars
if (password.match(/^\w+$/) || password.match(/^\d+$/) ) score -= 10;
//verifing 0 < score < 100
score = score * 2;
if ( score < 0 ) score = 0;
if ( score > 100 ) score = 100;
if (score > 25 ) r_class = 'okay-password';
if (score > 50 ) r_class = 'good-password';
if (score > 75 ) r_class = 'strong-password';
target.width(score + '%').removeClass("weak-password okay-password good-password strong-password"
).addClass(r_class);
return true;
};
基本的に、主要なタイプの攻撃を防ぎたい
前者を防ぐには、一般的な単語を含むパスワードは弱いと考えてください。後者を防ぐには、妥当な長さ (8 文字以上が一般的) で、適度に大きな文字セット (文字、数字、および特殊文字を含む) のパスワードを使用することをお勧めします。小文字と大文字が異なると考えると、文字セットが大幅に増加します。ただし、これにより、一部のユーザー コミュニティでは使いやすさの問題が生じるため、その考慮事項のバランスを取る必要があります。
簡単な Google 検索で、ブルート フォース攻撃 (複雑なパスワード) を説明するソリューションが見つかりましたが、辞書攻撃は説明しませんでした。この強度チェッカーのリストに含まれる PHP パスワード強度メーターはサーバー側でチェックを実行するため、辞書をチェックするように拡張できます。
編集:
ところで...ユーザーごとのログイン試行回数も制限する必要があります。これにより、両方のタイプの攻撃の可能性が低くなります。効果的ですがユーザーフレンドリーではないのは、X回の不正な試みの後にアカウントをロックし、パスワードのリセットを要求することです. よりユーザー フレンドリーになりますが、ログイン試行間の時間を調整するための労力が増えます。また、最初の数回のログイン試行後にCAPTCHAを要求することもできます (これは、スタック オーバーフローが多くの編集を行った後、または非常に新しいユーザーに対して要求するものです)。
Daren Schwenke が指摘したように、自分でセキュリティに取り組み、これをユーザーの手に委ねない方がよいでしょう。
ただし、パスワードを取得する最善の方法は依然としてソーシャル エンジニアリングであるため、パスワードの強度についてユーザーにヒントを提供することは良いことです。
したがって、ユーザーのパスワード強度を礼儀の指標としてリアルタイムでチェックする小さなクライアント側スクリプトをハックできます。それは何もブロックしませんが、緑色に変わると彼に良い暖かさを与えます:-)
基本的に、確認する必要があるのは常識です。パスワードに文字、数字、およびアルファベット以外の文字が妥当な量で含まれているかどうかを確認してください。
独自のアルゴリズムを非常に簡単にハックできます: 10/10 マークを付けるだけです:
神のようなパスワードをチェックする必要はありません (大文字の文字があるか、特殊な文字がどこに配置されているかなど)、ユーザーは銀行/軍事/秘密サービス/毎月の python 映画業界にいませんか?
クレイジーな JavaScript スキルがなくても、1 時間でコーディングできます。
とにかく、パスワードを有効にして、すべてのセキュリティ コードをサーバー側に移動します。認証 (例: オープン ID) を委任できる場合は、さらに優れています。
基本的に、正規表現を使用してパスワードの長さと複雑さを検証することをお勧めします。
JavaScript を使用してこれを行う良い例は、次の場所にあります。
http://marketingtechblog.com/programming/javascript-password-strength/
パスワードの強度をチェックするための特定のアルゴリズムを考えることはできません。私たちが行うことは、いくつかの基準を定義し、パスワードが基準を尊重する場合、そのスコアに1を追加することです。パスワードがしきい値に達すると、パスワードは強力になります。そうでなければそれは弱いです。
しきい値が異なる場合は、さまざまなレベルの強度を定義できます。または、特定の基準に対してさまざまな値を定義できます。たとえば、パスワードが5文字の場合は1を追加し、10文字の場合は2を追加します。
これがチェックする基準のリストです
長さ(8〜12で構いませんが、多いほど良いです)小文字が含まれています大文字が含まれています大文字は最初の文字ではありません。数字を含む記号を含む最後の文字は人間のような記号ではありません(例:。または!)辞書の単語のようには見えません。いくつかの賢明なパスワードクラックには、単語と文字の代替のライブラリが含まれています(Library-> L1br @ ryなど)
お役に立てば幸いです。