web-dev-qa-db-ja.com

グローバルソルトでどのように安全を確保できますか?

パスワードのハッシュと保存の基本を理解した場合、必要なものは次のとおりです。

  1. 「強い」塩
  2. 「実際の」ランダムソルト
  3. パスワードごとに一意のソルト
  4. aパスワードハッシュCPUコストが高い関数

PHP crypt()および_CRYPT_BLOWFISH_を使用して、「中」のコストで1、2、3、および4を使用してパスワードをハッシュします。

新しいニーズがあります。低レベルの詐欺/スパム/詐欺師が同じパスワードを使用していることに気付いたので、ハッシュを比較できるようにする必要があります。不正行為者のパスワードを知る必要はありませんが、以前に特定された不正行為者と同じパスワードをプロファイルが使用していることを知るだけで済みます。

したがって、データベースに2つのフィールドがあることを考えています。

  • passwordA:ログイン手順に使用されます(このフィールドは1、2、3、4を使用します)

crypt($password, '$2y$06$' . $uniqueSalt);

  • passwordB:「比較」に使用されます(このフィールドは1、2、4になります)

crypt(md5(md5($password) . $globalSaltA) . $globalSaltB, '$2y$10$' . $globalSaltC);

グローバルソルトAおよびBは、アプリケーションコードにのみ格納されます。

PasswordBの不足点3を補うために、はるかに高い「コスト」を増やしました。

コメントに続いて、攻撃者がサーバーでフルアクセス(データベース+コード)を取得した場合、この戦略がいかに安全でないかを理解しました。ただし、攻撃者がデータベースのみを取得する場合は問題ありません。

クレジットカード詐欺の検出を行う企業は、クレジットカード番号に関して同じ問題を抱えています。保管することはできませんが、比較する必要があります。

それでは、どのような戦略/解決策をアドバイスしますか?

11
Toto

主な問題:サーバーがハッシュされたパスワードを(潜在的に)と効率的に比較できる場合allすべてのユーザーのハッシュされたパスワード、それから攻撃者もそうすることができます。サーバーファイル/データベースのコピーを取得する攻撃者は、オフライン辞書攻撃を実行する可能性があります。つまり、潜在的なパスワードをハッシュして一致を探します。

通常のパスワードハッシュでは、パスワードごとのソルトを使用して、並列攻撃を防止します。攻撃者は、各パスワードに対してハッシュ関数の計算コスト全体を支払う必要があります(これは多くの反復により高価になります)and各ユーザーアカウント。ただし、複数のパスワードハッシュが同じソルトを使用している場合、攻撃者は1つのハッシュ関数呼び出しのコストですべてのパスワードハッシュに対して潜在的なパスワードを試すことができます。したがって、「グローバルソルト」はスキームを大幅に弱体化します。これにより、攻撃者は1つのアカウントを攻撃するコストで1000個のアカウントを攻撃できます。

重要なポイント:あなたの問題は一時性の1つです。実際、実際には、新しいユーザーのパスワードを他のすべてのユーザーのすべてのパスワードと比較する必要はありません。必要なのは、登録時に各ユーザーが選択したパスワードを、「既知の犯罪者のパスワード」の限定リストと比較することです。残念ながら、登録されたユーザーが「犯罪者」ステータスになると、彼はすでに登録されており、彼のパスワードは保持されておらず、そのハッシュのみが保持されています。したがって、実際には、登録に使用するパスワードにアクセスできるようにしたいと思いますafter登録が行われました。

可能な解決策:エスクローを使用、別名 非対称暗号化 。 RSAキーペアを作成します。公開鍵をサーバーに保管します。対応する秘密鍵をサーバーに保存しないでください。代わりに、他の場所に保管してください。オフラインに保たれているラップトップコンピューター(またはおそらくいくつかのUSBフラッシュドライブ上)。

ユーザーが登録するときに、通常どおりにパスワードをハッシュします(PBKDF2、多くの反復、新しいランダムソルトなどを使用)。しかし、また、encrypt RSAキーを使用したパスワード(ハッシュではない)であり、暗号化の結果をハッシュとともにデータベースに格納します。暗号化は公開鍵のみを必要とし、ランダム化されるため、この暗号化されたバージョンは、データベースの内容のコピーを取得する攻撃者に余計な影響を与えません。ユーザーがログインすると、通常どおりパスワードハッシュが使用されます。

ユーザーがスパマーであることが判明したら、秘密鍵を取得し、エスクローされたパスワードを復号化します。このようにして、「不正なパスワード」を取得し、それをパスワードのリストに追加して、登録時に拒否することができます。このリストは平文のままにしておくことができます。対応するアカウントが閉鎖されているため、問題はありません。 「安全な」マシンで、できればオフラインで復号化を実行するように注意してください。秘密鍵が盗まれたのを見たくないのです。


注意:スパマーは細菌のようであり、外部の制約に関して進化する傾向があります。登録のためにパスワードを再利用する習慣に基づいてスパマーを除外すると、すぐにランダムなパスワードを生成するように訓練されます。したがって、そのようなシステムをインストールすると、比較的短時間でスパマーを追い出すのに効果的でなくなると予測します。その後は、データベースでは重荷になります(2048ビットのRSAキーを持つRSA暗号化されたショートメッセージはわずか256バイトですが、それでも重荷です)。

12
Thomas Pornin

できません。独自のソルト(またはそのことについては任意のソルト)を持つというセキュリティを完全に無効にします。独自のソルトを持つことのポイントは、レインボーテーブルを使用してパスワードを特定できないことです。グローバルソルトを使用して保存すると、そのテーブルがRainbowテーブルで攻撃され、多くの場合、元のパスワードを特定できます。

これに代わる方法は、新しいパスワード(以前のスパマーに関連付けられていたもの)に対して試行するソルトのリストを生成することです。パスワードハッシュを複数回実行する必要があるため、新しいユーザーの作成は少し難しい操作になりますが、これはあなたが話していることを行う唯一の安全な方法です。新しいユーザーの作成も、この手順を実行する必要がある唯一のタイミングであるべきなので、あまりにも多くのヒットになるべきではありません。また、影響をさらに減らしたい場合は、他のインジケーターがスパムユーザーであることをサポートしていると思われる場合にのみ実行することをお勧めします。

また、リストを短く保つために、不正なパスワードが特定された後に保存することもできます。たとえば、salt 1234を持つ以前のユーザーはハッシュabcdを持っていました。新しいユーザーがパスワード「ImSpam」を送信し、salt 1234に対してそれを試みると、それがabcdであることがわかり、そのsaltの実際のパスワードがわかったので、それに対するチェックを停止し、パスワードのみを完全に拒否できます。これにより、リストは比較的短くなります。また、そのスパマーにしばらくの間攻撃されていなければ、チャンスをあきらめている可能性が高いため、古いスパムユーザーを期限切れにする可能性もあります。

3
AJ Henderson

一意にソルトされたハッシュを「より良い」と呼び、グローバル/シングルソルトのハッシュを「より悪い」と呼びましょう。パフォーマンス上の理由から、ユーザーをより速く認証できるように、ユーザーデータベースでより良いハッシュを維持したい場合があります。 「悪い」ハッシュを、AddPassword(userId、password)とBlacklist(spammerUserId)の2つのメソッドで構成されるシンでシンプルな認証済みインターフェースを持つ、より安全な別のサーバーに移動することをお勧めします。

AddPasswordは単に成功または失敗を報告します。ブラックリストはスパマーのIDをブラックリストに追加し、スパマーのパスワードに一致するすべてのユーザーIDのリストを返します。ただし、注意してください。アクセス権を持つユーザーは誰でも、ブラックリストメソッドに対して辞書を実行し、正当なユーザーを中毒させ、一致するパスワードのリストを取得できます。

内部的には、ハッシュ化、ソルト化、暗号化、クリアテキストなど、好きなように保存できます。そのマシンを安全にロックしておく必要があります。

0
John Deters

@AJHendersonがすでに言ったように、簡単な答えはあなたができないということです。独自のソルトが必要な理由を理解し、このための数学的トリックを見逃していないので、独自のソルトと組み合わせることは本当に不可能です。とはいえ、これが私が問題を解決する方法です:

1. UnsaltedPasswordなどの新しいデータベースフィールドを追加して、すべてのNULL値を入力します。誰かが自分のパスワードを登録または変更するたびに、ソルトなしで、他のハッシュ方式よりも10倍強力なパスワードのハッシュを入力します。

2.ログインプロシージャを変更して、ユーザーがそのフィールドにNULL値を持っているかどうかをチェックし、ユーザーが持っている場合はフィールドに入力します。これにより負荷が大きすぎる場合は、ポストカウントが低い人や単に偶然の確率など、特定のアカウントに対してのみハッシュ機能を実行します(たとえば、10分の1の確率でハッシュを実行します)。

3.最後に、フィールドに入力するたびにパスワードの重複をチェックし、ブラックリストもチェックします。重複している人にはフラグが付けられる可能性があり(弱いパスワードを使用している可能性もある)、ブラックリストはすぐに禁止されます(または、可能であれば地獄の禁止)。

ログインと比較してパスワードの変更が頻繁に発生することはありません(他のハッシュ関数withソルトを実行する必要があります)ので、データベース内に2つの異なるハッシュフィールドがあることは理にかなっていると思います異なる目的。また、10倍強力な処理を実行できるようにする必要があります。それ以上の処理を実行することもできます(1〜2秒のハッシュ時間は、ほぼ1回限りの取引であるため、私が目指しているものです)。攻撃者がこれらを解読することは、独自のソルトを適用することよりもおそらく高価です。

0
Luc