私は現在 OpenwallのPHPass を使用しているサイトのパスワードストレージのセキュリティを改善する任務を負っています。すべてのハッシュが一度に変換されます。 e。ユーザーがログインしてパスワードを再ハッシュするのを待ちたくありません。
これを実現するために、私は既存のPHPassハッシュに対してbcryptを使用できると考えました(bcrypt(phpass(password))
)。
ただし、重要な中間ステップが必要です。bcryptと同様に、PHPassにはハッシュに埋め込まれた独自のソルトがあるため、ハッシュを検証するときに操作を繰り返し可能にしたい場合は、そのソルトをbcryptに「運ぶ」必要があります。
幸い、PHPassのソルトサイズはbcryptのソルトサイズ(16バイト)よりも小さい(6バイト)ので、ソルトの最初の6バイトを「共有」し、bcryptに10個のランダムバイトを追加できます。
擬似PHPで次のようなものを想像してみてください。
_$password = 'somestring123';
$hash = phpass($password)
// $hash is now '$H$9Uvsrbh2Wxo3SebfGb4xVtODMmD2K70',
// where 'Uvsrbh2W' is an encoded, random salt of 6 'raw' bytes
$raw_salt = decode(substr($hash, 4, 8));
$hash = bcrypt_with_custom_salt($hash, $raw_salt . random_bytes(10));
// $hash is now '$2y$12$Uvsrbh2WzN9HrapVpnmu2OYOdJ2jnjHt2LTwIYQPJe.BUJQKezKuO'
// whose salt uses the first 6 bytes we had in phpass,
// so that we can repeat the process when veryfing the password
// since we have all the salts available in only one hash
_
実装のバグを除外し、ランダムなソースが暗号的に安全であると想定しますこれは、レガシーコンテキストでbcryptを使用する理論的に安全な方法ですか?結果を理解してbcrypt(password)
を実行するのと同じくらい安全(これ以上...?)である必要がありますが、私は専門家ではないため、不明な点が見落とされている可能性があります詳細。
PHPassのbcryptでの1回限りのラッピングにより、オフラインのブルートフォース耐性が大幅に向上するはずです。上記でコメントしたように、デフォルトの作業係数を使用すると、hashcatはクラックする可能性があります PHPassフォールバック md5cryptスタイルのPHPassは、bcryptよりも約500倍高速です。
内側のPHPass saltを外側のbcryptで使用することは合理的であるようです。 (それは確かに静的ソルトよりも優れているようです!)あなたのレガシーbcryptソルトはかなりランダムではありません-非ランダム攻撃者にまだ知られていない内部のPHPassハッシュに対して相対的です。
各bcryptとPHPassは、それらのタイプの他のすべてのハッシュと比較してランダムにソルト化されるため、ソルトのdistributionは、ソルトがブルートフォースに対して幅広い抵抗力を提供しますだと思う。
PHPassソルトを事前に知っていることで、攻撃者に追加の利点をもたらす方法は考えられません。そして、それがslightの利点を提供する場合でも、ほぼ確実にbcryptを解読するコストが高いことを上回ります。
私は最初にこれを「 why-is-hashing-a-password-with-multiple-hash-functions-useless 」の複製として閉じるつもりでしたが、あなたはあなたに少し複雑なケースがありますすでにハッシュされたパスワードのデータベースがあります。
既存のハッシュメカニズムでは不十分であると考える場合は、より良いソリューションに移行する必要があります。つまり、古い表現と新しい表現を区別し、検証メカニズムを並行して実行し、クリアテキストを古い表現から新しい表現に変換できる必要があります。クリアテキストを取得できるのは、誰かがログインしたときだけです。
PHPPassはかなり長いですが、フグを使用します(フグではbcryptがベースです)。つまり、セキュリティを思ったほど改善していないのかもしれません。
Phpassから離れる場合は、可能な限りコードベースから削除したいと思うでしょう。最初にすべてのphpassesをbcryptされたバージョンのphpassesに置き換え、次にユーザーが次にログインするときにphpassハッシュをbcryptハッシュに置き換えることをお勧めします。切り替え以来初めてログインするユーザーをサポートするために、また、phpassが一致するかどうかを確認する必要もあります。
したがって、次のようなものです。関数が「bcrypt」と呼ばれていないため、明らかに私は疑似コードを使用しています。
if bcrypt(phpass($supplied_password)) == $storred_password;
$storred_password = bcrypt($supplied_password);
login();
if bcrypt($supplied_password) == $storred_password;
login();
このシナリオでは、新しいパスワードスキームに徐々に移行していますが、古いパスワードスキームは引き続きサポートされています。
Phpassにメモリリークなどの脆弱性がある場合は、ユーザーがログインするときに、ほとんどのパスワードでこの脆弱性をまったく使用していません。
あなたがしていることは本質的には キー拡張 です。しかし、phpPassはすでにこれを行っています(bcrypt
もそうです)。したがって、セキュリティの観点から本当にしていることは(わずかに)増加していますラウンドをもう1つ追加することによるセキュリティ。
PhpPassに実装の脆弱性があり、キーの開示につながる可能性があります(メモリバッファーのサニタイズを行わないなど)が、悪用される可能性は少ないようです。
概して、セキュリティを大幅に増加しなくても、セキュリティを低下させないと私は言います。
それでも、データベースを移行するいくつかの方法は、追求する価値があります。たとえば、ユーザーテーブルにフィールドを追加して、純粋なbcryptハッシュ(またはNULL)を保持します。 NULLの場合、phpPassアルゴリズムが使用され、パスワードが検証されると、bcryptフィールドが生成されます。 bcryptで満たされたハッシュフィールドの割合を監視して、移行の進行状況を確認できます。そして、いくつかのテスト移行ユーザーのphpPassハッシュをゼロにして、bcryptだけで立っているときにすべてが機能していることを確認できます(システムがきれいに設計されている場合、これは不必要ですが、ハッピーデイシナリオをCEO-コードカバレッジのあるテーブルはそれをそれほど切りません。