13

サイトをRailsに切り替えています。これは、50,000 人以上のユーザーを抱える非常に大きなサイトです。問題は、既存のパスワード ハッシュ方法が非常に弱いことです。2 つのオプションがあります。

1) 新しいアルゴリズムに切り替え、すべての人にランダムなパスワードを生成し、それらのパスワードを電子メールで送信して、直後に変更を要求する

2)新しいアルゴリズムを実装しますが、以前の古いアルゴリズムを使用してから結果をハッシュします。例えば:

パスワード: abcdef =アルゴリズム 1 => xj31ndn =アルゴリズム 2 => $21aafadsada214

新しいパスワードは、元のアルゴリズム (md5) を通過する必要があり、それが意味をなす場合、その結果をハッシュする必要がありますか? これに何かデメリットはありますか?

4

4 に答える 4

22

通常、パスワードをリセットする必要はありません。ユーザーが次回ログインするまで待つことができます。

  1. 最初に、入力したパスワードを新しいアルゴリズムで検証してみます。新しいパスワードと既に変換されたパスワードは、検証に時間がかかりません。
  2. 一致しない場合は、古いハッシュ アルゴリズムと比較します。
  3. 古いハッシュ値が一致する場合は、パスワードがわかっているため、新しいハッシュを計算して保存できます。

すべてのパスワード保存システムには、より優れたハッシュ アルゴリズムに切り替えるオプションが必要です。問題は 1 回限りの移行の問題ではありません。BCrypt のような優れたパスワード ハッシュ アルゴリズムにはコスト ファクターがあり、(ハードウェアが高速であるため) 時々このコスト ファクターを増やす必要があり、移行に必要な手順とまったく同じ手順が必要になります。

最初のアルゴリズムが非常に弱く、すぐに保護を強化したい場合は、古いハッシュをハッシュするオプション 2 が適しています。この場合、ダブル ハッシュを計算し、データベース内の古いハッシュを新しいダブル ハッシュに置き換えることができます。

$newHashToStoreInTheDb = new_hash($oldHashFromDb)

また、このパスワード ハッシュをマークする必要があります (理由を参照)。これにより、ダブル ハッシュとして認識できます。これは別のデータベース フィールドで行うことも、独自の署名を含めることもできます。最新のパスワード ハッシュ関数には、アルゴリズムの署名も含まれているため、新しいアルゴリズムにアップグレードし、古いハッシュを検証することもできます。この例は、BCrypt ハッシュの署名を示しています。

$2y$10$nOUIs5kJ7naTuTFkBy1veuK0kSxUFXfuaOKdOKf9xYT0KKIGSJwFa
___
 |
 signature of hash-algorithm = 2y = BCrypt

検証は次のように実行されます。

  1. ダブルハッシュかどうかを判断します。
  2. 新しいハッシュの場合は、新しいハッシュ関数を呼び出して、入力したパスワードを確認します。これで完了です。
  3. ダブル ハッシュの場合は、ダブル ハッシュ アルゴリズムと比較しますnew_hash(old_hash($password))
  4. ダブル ハッシュ値が一致する場合は、新しいハッシュを計算して保存できます。
于 2013-01-18T15:46:16.297 に答える
10

最も簡単な解決策は、おそらく「パスワード ハッシュ タイプ」列をデータベースに追加することです。最初は「old」に設定します。ユーザーのログイン時に、新しいアルゴリズムを使用してパスワードを再ハッシュし、データベース タイプを「new」に設定します。

このメソッドの変形は、ハッシュ タイプをハッシュ文字列の一部として保存することです。これは、さまざまなハッシュ形式を明確に区別できる限り同様に機能し、他の必要なパラメーター (ソルトやキーストレッチングの作業係数など) を同じ文字列に含めることができるという利点があります。それぞれの追加フィールドをデータベースに追加する必要があります。

たとえば、これは現代の Unix crypt(3) 実装(およびPHPなどのさまざまな高水準言語の対応する関数) で通常使用されるアプローチです: 古典的な DES ベースの (そして恐ろしく弱い) パスワード ハッシュは次のようabJnggxhB/yWIになります。 (少し) より現代的なハッシュはのよう$1$z75qouSC$nNVPAk1FTd0yVd62S3sjR1に見えるかもしれません。1指定されたハッシュ方法z75qouSCは、salt とnNVPAk1FTd0yVd62S3sjR1実際のハッシュであり、デリミタ$は古いスタイルの DES ハッシュには表示されないため選択されます。


あなたが提案する方法。新しいハッシュは次のように計算されます。

 hash = new_hash( old_hash( password ) )

ユーザーがログインするのを待たずに既存のすべてのレコードを更新できるため、場合によっては便利です。ただし、古いハッシュ関数がパスワードのエントロピーを十分に保持している場合にのみ安全です。

たとえば、unsalted MD5のようなかなり古くて弱い暗号化ハッシュ関数でも十分です。その出力は入力全体に依存し、最大 128 ビットのエントロピーを持ちます。これは、ほとんどのパスワードよりも大きい (およびとにかく、総当たり攻撃に耐えるには十分すぎる)。一方、古い DES ベースの crypt(3) 関数を古いハッシュとして使用してこの構造を適用しようとすると、悲惨なことになります。それらの文字の最上位ビットも)。

于 2013-01-18T16:53:00.267 に答える
2

新しいパスワード方式でパスワードを更新したすべてのユーザーで新しいパスワード フィールドを作成し、オプション 2 で全員を更新することができます。

これを、古いパスワード方式を使用するすべてのユーザーのログイン時にパスワードの更新を強制することと組み合わせると、アクティブなすべてのユーザーが自動的に新しいパスワード方式に移行します。

于 2013-01-18T13:24:43.290 に答える
1

別の方法として、移行フェーズで両方のハッシュをデータベースの別々の列で使用できるようにしておくこともできます。

  • ログイン時に新しいハッシュが存在しない場合は、古いハッシュで確認し、新しいハッシュを保存して、古いハッシュを削除します。
  • 新しいハッシュが存在する場合は、これのみを使用して検証します。

したがって、しばらくすると、少なくとも 1 回ログインしたユーザーについては、新しいハッシュのみが残ります。

于 2013-01-18T13:25:32.267 に答える