web-dev-qa-db-ja.com

ハッシュ関数の変更

安全でない(古い)暗号化ハッシュ関数を使用して、ユーザーアカウントのパスワードをデータベースに保存しています。

パスワードハッシュ関数を変更するための最良/通常のアプローチは何ですか?私の頭に浮かぶのは2つのアイデアだけです。

  1. すべてのユーザーに次回のログイン時にパスワードを変更するように求め、パスワードを変更する場合は新しい機能でパスワードをハッシュします。これは、多くの問題(非アクティブなユーザー、長い移行期間、複雑な実装など)のため、適切なオプションではありません。

  2. 新しいハッシュ関数で古いハッシュ値をハッシュし、データベースに対してパスワードをチェックするメソッドを書き直します:newHash(salt + oldHash(salt + password))

このダブルハッシュは、エレガントで簡単に実装できる優れたアイデアのようです。

ここで気づいていない警告があるかどうか知りたいのですが。これは通常行われる方法ですか、それとも別の方法がありますか?弱いハッシュ関数の出力を強いハッシュ関数の入力として使用する際に、既知の暗号化の脆弱性はありますか?.

それが良い考えであるなら、塩はどうですか?両方のハッシュ関数に同じソルトを使用しても大丈夫でしょうか?

28
h9lpq0u

個人的には、新しいユーザーが強力な最新のハッシュ(bcryptまたは他のキー強化された暗号化ハッシュ)を取得する古いユーザーと、弱いユーザーがbcryptをラップしている古いユーザーの両方を実装するでしょう。人々が実装の複雑さに不満を言う前に、代わりに、常に新しいユーザーに強力なハッシュアルゴリズムにラップされた弱いハッシュアルゴリズムを使用するように強制することです。つまり、元のスキームがなくなることはありません。

私はcryptで$1$$2a$$5$、または$6$に類似したタイプハッシュスキームの文書化されたインジケーターを持っています(cryptのマニュアルページからの引用)。

   If  salt is a character string starting with the characters "$id$" fol‐
   lowed by a string terminated by "$":

          $id$salt$encrypted

   ... id  identifies  the  encryption
   method  used  and  this  then  determines  how the rest of the password
   string is interpreted.  The following values of id are supported:

          ID  | Method
          ─────────────────────────────────────────────────────────
          1   | MD5
          2a  | Blowfish (not in mainline glibc; added in some
              | Linux distributions)
          5   | SHA-256 (since glibc 2.7)
          6   | SHA-512 (since glibc 2.7)

この場合、3種類のパスワードハッシュが必要です。

  1. 古い高速の弱いハッシュ
  2. 強力なソルトで低速ハッシュを包む古い高速で弱いハッシュ
  3. 新しいスローハッシュ。

1日目、カテゴリ1からすべてを取り出してカテゴリ2に移動します。新しいパスワードはカテゴリ3に入れられます。さらに、ログインすると、正常に認証されたすべてのハッシュをカテゴリ2からカテゴリ3に移行しながら、プレーンテキストパスワードはメモリにあります。ある時点で、弱いハッシュスキームの証拠/レガシーメンテナンスを完全に排除することもできます。 (たとえば、変更後2年以上ログインしていないアカウントを持つユーザーにパスワードのリセットを強制する)。

19
dr jimbob

あなたの提案2(古いハッシュ値を新しいハッシュの「パスワード」として使用する)は適切ですif以下の条件がすべて当てはまります。

  • 古いハッシュは preimages に対して十分な耐性があります。
  • 新しいハッシュは、必要なすべてのベルホイッスルを使用して「ロバスト」であると見なします(つまり、 bcrypt であり、ラウンド数が多く、各パスワードに新しいランダムソルトが含まれます。ユーザー)。
  • 古いハッシュは、「構成可能な遅延」ビジネス全体が新しいハッシュのみに依存するように十分効率的に計算できます。

MD5は衝突に関しては完全に壊れていますが、プリイメージに関してはまだかなり強いように見えます。

移行をスムーズに処理できるように、データベースに「ハッシュのタイプ」フィールドを含めることは、それでも最善の方法です。たとえば、ハッシュオブハッシュを適用し、新しいハッシュのみを使用するパスワードハッシュスキームへの移行を計画できます。パスワードは、作成または変更されるたびに新しいスキームに更新されます。段階的な移行。後で(たとえば1年後に)、古い形式を使用しているパスワードの強制更新(ユーザーは次回ログイン時にパスワードを再入力する必要があります)をセットアップできます。

移行が気に入らなくても(誰が?)、その時の状況によって移行が強制される場合(例:壊滅的な暗号解読)、将来の移行の可能性に備えて準備するのが賢明なようです。

11
Thomas Pornin

新しいハッシュとして bcrypt を使用します。それ以外の場合、bcryptに適切なソルトを使用すれば、古いハッシュを「ラップ」するソリューションは安全になります。システムがパスワードをハッシュする方法をアップグレードしたいときに、このソリューションが数回うまくいくことを確認しました。

7
Oleksi

古いハッシュ関数を使用したくないが、全員にパスワードの変更を強制したくない場合は、エレガントな解決策が1つあります。

すべてのユーザープロファイルに列/値を追加します。 HashVersionなら呼び出しましょう

移行後、ユーザーが初めてログインすると、システムは古いハッシュ関数を使用してそれを検出できます。したがって、ユーザーが指定したパスワードがハッシュと一致する場合は、プレーンテキストのパスワードを取得して、新しいアルゴリズムでハッシュし、ソルトなどをリセットします。次に、HashVersionを上げて、新しいハッシュ関数が使用されていることを確認します。

これは、私の意見では、特に以前のハッシュ関数が本当に安全でなかった場合、最良の解決策です。

7
Earlz

古いハッシュが適切である限り(MD5またはDES-Cryptは問題ありませんが、CRC32は問題ありません)、このアプローチは安全です。同じソルトを使用しても問題は発生しません。ソルトが十分に優れている、つまり(ほぼ)グローバルに一意であると想定します。

外部ハッシュ関数については、scrypt、bcrypt、またはPBKDF2のいずれかを使用することをお勧めします。

3
CodesInChaos

この問題を解決した数十のオープンソースアプリケーションが見つかります。 Wordpressがすぐに思い浮かびますが、他にもあります。MicrosoftWindowsでもこれと同じ手法を使用しています。一般的な解決策は次のとおりです。

  • サポートされている各ハッシュ関数の出力はすぐに区別されます。出力形式または長さをチェックするか、(より適切には)識別子文字列を前に付けることにより(例:sha1:salt:_hash_output____)または、データベースに新しいフィールドを追加して、ハッシュタイプを識別します。
  • 以前使用したすべてのハッシュ関数による認証を引き続きサポートしますが、すべての新しいハッシュは優先バージョンのみを出力します。
  • オプションで、ユーザーが以前のハッシュバージョンを使用して認証された場合、認証されたパスワードは優先アルゴリズムを使用して再ハッシュされ、保存されているハッシュが更新されます。
1
tylerl