web-dev-qa-db-ja.com

基になるメソッドが変更されたときにパスワードを自動的にリセットする必要があります

私は現在、開発フェーズのプロジェクトのエンジニアです。このプロジェクトの1つの「モジュール」は、ユーザー認証/承認の機能を提供します。ただし、パスワードハッシュアルゴリズムがcop(別名BCrypt)に対応していない可能性があることが懸念されます。 (恐ろしいことは、それが何で、どこから来たのかははっきりしていません!).

これは明らかに変更する必要があり、パッチはスケジュールされています。パスワードは古いハッシュ方式を使用しているため、すべてのテストユーザーを自然に更新する必要があります。それほど問題ではありません。すべてのデモユーザーはビルド時に自動化されているため、スクリプトが更新されます。しかし、次の問題は、これがアクティブで古くなったユーザーがすべての量の本番システムである場合はどうでしょうか。ベストプラクティスは何でしょうか。

  1. すべてのユーザーのパスワードを自動的にリセットしますか?これにより、すべてのユーザーにパスワードが変更されたことが通知され、質問や混乱を引き起こしたり、セキュリティ違反が疑われたりする可能性があります。ウェブサイトの関係者が必ずしも回答できるとは限らない、より多くの質問が求められる場合があります。
  2. 新しい方法か古い方法かを示すフラグを設定するようにDBを更新します。その後、ユーザーが認証されると、使用しているDBのパスワードを更新します。サービスに少しロジックが必要で、移行は既存のユーザーには見えません。問題は、違反があった場合、ここで2つの方法が実行されていることと、安全性の低い方法が安全でないことが判明した場合、明らかに破壊される可能性があることです。
  3. 既存のハッシュのBCryptedバージョンを使用して、すべてのパスワードをリセットします。古いスタイルとしてフラグを立てるので、認証が成功すると、ハッシュのハッシュではなくパスワードのハッシュが保持されます。
94
Crazy Dino

オプション1.は悪い考えです。ユーザーエクスペリエンス/パブリックリレーションの理由に加えて、パスワードリセットトークンを傍受してサーバー上のすべてのアカウントを侵害するためのウィンドウを攻撃者に与えることもできます。怠惰でログイン/パスワードの更新ができないユーザーが1人でもいる場合も、問題は解決しません。

一見すると、2。と3.はどちらも問題ないように見えます。あなたの#2は今していることよりも安全ですが、2。は現在の弱いログインを永久にサポートし続ける必要があることを意味します(または、「Xか月後にパスワードを消去して強制的に実行します。必要なニースのユーザーの透明性を損なう回復」を無視します)。

二度とログインしないユーザーがDBにいる場合を考えてみましょう。 2.と3.の両方で、ログインした場合に備えて、コードベースで現在のハッシュalgを永久にサポートし続ける必要がありますが、少なくとも3.には、ユーザー(またはユーザー)が保護されているという利点があります。 DBが盗まれた場合のオフラインの総当たり攻撃。

「古いスタイルのフラグ」列を永久に保持する必要があるので、自分でお願いし、intではなくboolにしてください。これにより、パスワードハッシュalgを再度更新する必要がある場合は、which古いスタイル。


更新:非常によく似た質問が尋ねられました ここ で、このスレッドからの議論に基づいています。

89
Mike Ounsworth

オプション3を実行できる場合、他のユーザーを検討する理由がわかりません。それは断然最良の選択肢です。このオプションを使用すると、古いアルゴリズム用とbcryptを使用した新しいアルゴリズム用の2つの異なるソルトを使用することを考えるのが私の直感です。私はこのようなセットアップを想定しています:

  1. 今日から始めた場合と同じように、新しいパスワードシステムをセットアップします。
  2. ユーザー名(またはID)、ハッシュアルゴリズム(名前またはID)、ソルトのフィールドを持つ新しい個別のテーブルを作成します。
  3. ログイン時に、ユーザーが別のテーブルにレコードを持っているかどうかを確認し、レコードがある場合は、古い方法でパスワードをハッシュしてから、新しい方法で結果をハッシュし、bcryptハッシュと比較します。一致する場合は、新しい方法でパスワードを再ソルト/ハッシュし、別のテーブルからレコードを削除します。

欠点は、パスワードを数ミリ秒長くメモリに保持する必要があることです(問題ありません)。別のテーブルが空になるか、古いアカウントになるまで、ログインごとに追加のテーブルルックアップがほぼ永久に行われます。彼らが自分でパスワードをリセットするように彼らに要求しても構わないほど古くなっています。

14
TTT

OLDスキームがsaltでハッシュされている場合、saltを個別に保存しない限り、スキーム#3を使用できないことに注意してください。

通常、ソルトはハッシュと一緒に保存され、ハッシュ関数への入力としてソルトを使用します。まったく同じソルトを使用しない場合、完全に異なる出力が得られます。

Newhash(oldsalt + oldhash、newsalt)を実行すると、正しいパスワードを使用していても、oldsaltがないため、oldhashを再作成できず、最終的なハッシュを生成できません。同じことがパラメーターを持つものすべてに適用されます(たとえば、bcryptには「コスト」パラメーターがあります-これは暗号化時に設定する必要があり、パスワードの検証時に使用するために出力に埋め込まれます)。

[〜#〜]また[〜#〜]:他の人が述べたように、ハッシュが「古い」または「新しい」スタイルであることを保存している場合は、代わりに「スキーム」を保存することを検討してください-ここで、例えば0は「古い」、1はbcryptです(「新しい」は使用しないことに注意してください。現在は「新しい」であり、永久に「新しい」とは限りません!)。これを行う一般的な方法は、ハッシュの先頭にマーカーを置くことです(これは既に当てはまる場合があります)。 bcryptは、「$ 2a $」、「$ 2b $」、「$ 2x」、「$ 2y $」のいずれかの標準プレフィックスを使用します。 「古い」アルゴリズムの可能な出力に応じて、これらをマークするために独自の接頭辞を作成する必要がある場合があります。または、「 '$'で始まらないものはすべて古いアルゴリズムです。」.

そして最後に、明らかに古いパスワードのセキュリティに懸念を抱いているため(当然です!)、トークンを使用して指示を電子メールで送信することにより、全員にパスワードを変更するように強制することをお勧めします(絶対にしないでください!リンクを送信してください!ユーザーがリンクをクリックするだけです!通常の場所にログオンするように伝えてください)。次に、トークンとそのパスワードを要求します。そうしないと、過去にパスワードを盗んだことがある人がパスワードを変更して、有効な「新しい」パスワードを取得する可能性があります。

最後に:有効期限があります-この日付までにパスワードが変更されない場合は、無効にする必要があります。この日付はメールに記載する必要があり、あまり遠くない将来の予定です(1週間?は、顧客が応答するのにかかる時間によって異なります)。その後、「パスワードのリセット」手順を実行する必要があります。

3
AMADANON Inc.

パスワードのエンコード方式はわかりませんが、悪くない場合は、古い形式と新しい形式のパスワードの構造が異なる可能性があります。

古いBSDシステムで、システムが従来のパスワードエンコーディングからより安全なパスワードエンコーディングに変更されたとき、私はすでにそのようなものを見てきました。新しいものは、古いスキームには存在し得なかった文字シーケンスで始まったため、古いパスワードを持つユーザーがログインするたびに、その平文のパスワードが古い方法を使用して検証され、サイレントに再ハッシュされてパスワードデータベースに保存されました。新しいメソッド。 1か月後、データベースに古いパスワードは存在せず、エンドユーザーは何も通知しませんでした。

それは、2番目と3番目の方法の間のどこかにあります。

実際の運用Webシステムでは、ユーザーが再接続するまでに数週間または数か月も待機する可能性があるため、事態はさらに悪化する可能性があることを知っています。しかし、(実際のアクティビティによっては)数か月間接続していないユーザーがパスワードを忘れた可能性があるという事実によって軽減される可能性があります。または、パスワードを忘れた可能性があります。ここではおそらく3〜6か月長くなり、その後、すべての古いスタイルのパスワードを禁止された値にリセットし、ユーザーに次の接続時にパスワードをリセットするように強制します... パスワードを忘れた場合画面から。

ここでの良い点は次のとおりです。

  • 通常のユーザーに対して透過的
  • データベーススキーマの変更なし-パスワードフィールドが両方のスタイルを受け入れることができる場合
  • たまにしか使用しないユーザーは、数か月後にパスワードを使用せずにパスワードを忘れたかのように処理されます。

欠点は、認証方式とすべてのスタイルのパスワードの自動更新の両方を同時に実装する必要があることです。

2
Serge Ballesta

使用している言語については言及していません。 Phpには、場合によってはtrueを返す必要があるときにfalseを返す必要のあるさまざまな関数や、機能するように聞こえるが実際に可能な有効な入力全体を処理するロジックがない他の関数に問題があります。

しかし、これは、phpを使用していない場合でも、phpで話していることを実行する正しい方法です。高レベルのコードは、目的に合わせてコーディングする際の出発点となります。

http://php.net/manual/en/function.password-needs-rehash.php

$password = 'rasmuslerdorf';
$hash = '$2y$10$YCFsG6elYca568hBi2pZ0.3LDL5wjgxct1N8w/oLR/jfHsiQwCqTS';

// The cost parameter can change over time as hardware improves
$options = array('cost' => 11);

// Verify stored hash against plain-text password
if (password_verify($password, $hash)) {
    // Check if a newer hashing algorithm is available
    // or the cost has changed
    if (password_needs_rehash($hash, PASSWORD_DEFAULT, $options)) {
        // If so, create a new hash, and replace the old one
        $newHash = password_hash($password, PASSWORD_DEFAULT, $options);
    }

    // Log user in
}

私がやろうとしているのは、intを使用して言及された内容を持つ#2です。 PASSWORD_DEFAULTのドキュメントを読むと、より良いアルゴリズムが見つかると変更される可能性があり、phpがアップグレードされているため、セキュリティ上の理由から現在のアルゴリズムを削除する必要があります。

0
Eric