ユーザーはユーザー名/パスワードでログインし、ログインしたままにできるCookieを持っています。ユーザーは、JSの更新バージョンを実行することが期待されています。
誰かが私たちのデータベースをある時点で引っ掛かると仮定すると、
ユーザーにログイン時に妥当な作業証明のタスクを実行させ、それをパスワードとして送信することで、保存されているパスワードのエントロピーを減らし、長年にわたって難易度を上げることは良い考えですか?
これは何をしますか:
これがしないこと:
クライアント側の登録/ログイン:
h = password
d = "0000f"
do:
h = hash (h + username + salt)
while (h > d)
send("login", username, h)
サーバーサイドログイン:
d = "0000f"
listen("login", username, h)
if h > d:
user = database.get(username)
if user.pass == h:
send("accepted", true)
session.user = user
クライアント側ログインパート2:
listen("accepted", accepted)
if accepted:
set cookie("user", user)
set cookie("h", h)
これの利点は、ユーザーが難易度を更新するためにパスワードを再送信する必要がないことです。
私はこのプロトコルを実装しましたが、他のどこでもこれを見たことはありません。そして、暗号力学の第一法則は、「あなたは決して自分のものを転がすべきではない」です。
これが機能する場合、サーバーがユーザーのシークレットを責任を持って保存していることをユーザーに示すために、これが証明書に組み込まれるのを見てみたいです。
私はここの専門家ではありません。あなたのアイデアはきちんとしていて、私はそれを探究したいので、私の考えを投げ捨てます。
@ PwdRsch で指摘されているように、password14は [video] 、 [slides and sample code] 2014から(最強のトークではありませんが、私はこれまでに見たことがある)はまさにこのトピックです。
私はあなたのスキームの現状についていくつかの問題を抱えています。まず、リプレイ攻撃を防ぐには、ログインごとに実際にサーバーでナンスを生成し、これをクライアントに送信する必要があります(ナンスはキー強度である必要はなく、簡単なDoSを提示したくないため、通常の/dev/urandom
ではなく/dev/random
から入手してください)
次に、攻撃者と正直なユーザーの両方がO(hash_prefix = '0000')の作業を行う必要があります。これは、スマートフォンの正直なユーザーにとって、12 GPUハッシュリグの攻撃者よりもはるかに大きなペナルティになります。 。攻撃者に利点を与えることは悪いことです。
次のようにしてこれらを修正しましょう:
クライアント側:
h = "0"
d = "0000f"
hashed_pw = pbkdf2( password )
do:
h = hash (h + username + hashed_pw + nonce)
while (h > d)
send("login", username, h)
サーバ側:
listen("login", username, h)
user = database.get(username)
if "0000f" > hash (h + username + user.hashed_pw + nonce)
send("accepted", true)
session.user = user
ここでサーバーはO(1)作業(単一のハッシュ反復))を行う必要があり、正直なクライアントはO(hash_prefix = '0000')作業を行う必要があり、攻撃者は指数関数を行う必要がありますパスワードの長さで機能する:O(2password_length-1)* O(hash_prefix = '0000')。
アルゴリズムを少し強化しました(ただし、私が1時間かけてアルゴリズムをじっと見つめているので、それがすぐに使えることを意味しているわけではありません)。あなたの脅威モデルは、オンラインの総当たり攻撃から保護して、ユーザーのアカウントが侵害されるのを防ぐことだと思います。
この攻撃シナリオでは、攻撃者は 最も一般的なパスワードリスト のパスワードを使用するのに十分な馬鹿なユーザーを見つけようとしています。ここでは、攻撃者がパスワードを推測するように強制することによる指数関数的な高速化は、パスワードの指数的な数を推測していないため、消えています。したがって、弱いパスワードを使用するユーザーにとって、このスキームは実際には何もしていません。数ミリ秒のハッシュは攻撃者にとって重要ではないためです。
ここで、攻撃者は特定のアカウントに侵入しようとしています。彼らが本当にパスワードをランダムに推測している場合、これはそれらを遅くしますが、ネットワークの遅延とfail2banがすでにソーシャルエンジニアリング/フィッシング攻撃をオンラインの総当たりよりも優れていることを考えると、あなたが価値を追加しているとは思えませんここでも。これが心配な場合は、Google認証システムで2FAを有効にしてください。
ボトムライン:アイデアは素晴らしく、私はこれについて考えることを楽しんできましたが、
あなたの計画のさまざまな部分は、「それを行うための別の方法ですが何も害を及ぼさない」から「それは深刻なセキュリティの脆弱性」まで、有用性が異なると思います。詳細に:
おそらく標準外
通常、クライアント側でパスワードをハッシュ化しません。そうは言っても、パフォーマンス上の理由でクライアント側でハッシュを行うアプリケーションは他にもあると思いますので、これはおかしくありません。ただし、この場合、クライアント側のハッシュの結果としていくつかの選択を行ったと思いますare悪い。
異なるが、おそらくうまくいく
仕事関数が増えることは完全に正常であり、さらには良いことです。考えは、時間の変化に応じて、システム全体の仕事の価値を高め、パスワードの解読を困難にするというものです。明らかに理解しているように、ハッシュを作成するために実行する必要がある「反復」が多いほど、クラックの試行は反復回数と一致しなければならないため、パスワードをクラックするのは難しくなります。実際にそれを行うことに関して、ここにいくつかの重要な考慮事項があります:
1)(実際にはnitpick)。繰り返しハッシュしてもエントロピーはまったく変わりません。高いエントロピー=より安全であるため、アルゴリズムでエントロピーが減少している場合(回答で述べたように)、それは悪いことです。どちらの方法でも、増加する仕事関数は実際にはエントロピーを増加または減少させません。
2)計画の問題は、クライアント側で行うため、計算機能の進歩を説明するために時間の経過とともに仕事関数を調整できないことです。サーバー側を使用すると、時間の経過とともに作業関数を非常に簡単に更新できます。クラックをより高価にしたい場合は、ユーザーが次回ログインしたときに、より高い仕事関数でパスワードのハッシュを再計算するだけです。その後、パスワードと仕事関数の両方をデータベースに保存できます。サーバーがパスワードを見ることは決してないので、クライアントとサーバー間で追加のやり取りがなければ、ハッシュを更新することはできません。
潜在的に大きなセキュリティホール
これは巨大な問題だと思います:
set cookie("h", h)
問題は、ハッシュをCookieでクライアントに送り返すことです。問題のもう1つの部分は、サーバーがこの同じハッシュを直接受け入れてユーザーにログインすることです。したがって、ユーザーのパスワードをCookieに効果的に保存します。これは、これまでで最も安全性の低い場所です。そのCookieを盗んだ人は、ユーザーがパスワードを変更するまで、そのユーザーとしてログインできます。
通常、Cookieに保存するのはセッションIDだけであり、サーバー側ではそのセッションIDをログインユーザーに関連付けます。セッションIDが盗まれた場合(または侵害された疑いがある場合でも)、単にセッションIDを無効にすることができます。その後、攻撃者はすべてのアクセスを失い、正当なユーザーは再度ログインする必要があります。
どのような状況でも、パスワードまたはパスワードのハッシュをCookieに保存しないでください。ログインに成功した後は、どちらも完全に忘れられます(クライアント側)。