ふぐで長いパスワード(> 72文字)をハッシュする方法


91

先週私はパスワードハッシュに関する記事をたくさん読みましたが、Blowfishは現時点で最高のハッシュアルゴリズム(の1つ)のようですが、それはこの質問のトピックではありません。

72文字の制限

Blowfishは、入力されたパスワードの最初の72文字のみを考慮します。

<?php
$password = "Wow. This is a super secret and super, super long password. Let's add some special ch4r4ct3rs a#d everything is fine :)";
$hash = password_hash($password, PASSWORD_BCRYPT);
var_dump($password);

$input = substr($password, 0, 72);
var_dump($input);

var_dump(password_verify($input, $hash));
?>

出力は次のとおりです。

string(119) "Wow. This is a super secret and super, super long password. Let's add some special ch4r4ct3rs a#d everything is fine :)"
string(72) "Wow. This is a super secret and super, super long password. Let's add so"
bool(true)

ご覧のとおり、最初の72文字だけが重要です。Twitterはbfish(別名bcrypt)を使用してパスワード(https://shouldichangemypassword.com/twitter-hacked.php)を保存し、何を推測しているのかを確認します。Twitterのパスワードを72文字を超える長いパスワードに変更すれば、次の方法でアカウントにログインできます。最初の72文字だけを入力します。

ふぐと唐辛子

「ペッパー」パスワードについては、さまざまな意見があります。秘密のペッパー文字列も知られている/公開されているのでハッシュを強化しないため、これは不要だと言う人もいます。私は別のデータベースサーバーを持っているので、データベースだけがリークされ、一定のペッパーはリークされない可能性があります。

この場合(コショウが漏れていません)、辞書に基づく攻撃をより困難にします(これが正しくない場合は修正してください)。コショウのひもも漏れている場合:悪くはありません-まだ塩が残っていて、コショウなしのハッシュと同じように保護されています。

ですから、パスワードをペパーリングすることは少なくとも悪い選択ではないと思います。

提案

72文字(およびコショウ)を超えるパスワードのBlowfishハッシュを取得するための私の提案は次のとおりです。

<?php
$pepper = "foIwUVmkKGrGucNJMOkxkvcQ79iPNzP5OKlbIdGPCMTjJcDYnR";

// Generate Hash
$password = "Wow. This is a super secret and super, super long password. Let's add some special ch4r4ct3rs a#d everything is fine :)";
$password_peppered = hash_hmac('sha256', $password, $pepper);
$hash = password_hash($password_peppered, PASSWORD_BCRYPT);

// Check
$input = substr($password, 0, 72);
$input_peppered = hash_hmac('sha256', $input, $pepper);

var_dump(password_verify($input_peppered, $hash));
?>

これは、に基づいて、この質問password_verifyリターンfalse

質問

より安全な方法は何ですか?最初にSHA-256ハッシュ(64文字を返す)を取得しますか、それともパスワードの最初の72文字のみを考慮しますか?

長所

  • ユーザーは最初の72文字だけを入力してもログインできません
  • 文字数制限を超えずにコショウを追加できます
  • hash_hmacの出力は、おそらくパスワード自体よりもエントロピーが高いでしょう。
  • パスワードは2つの異なる関数によってハッシュされます

短所

  • フグのハッシュの作成に使用されるのは64文字のみです


編集1:この質問は、blowfish / bcryptのPHP統合のみを対象としています。コメントありがとうございます!


3
パスワードを切り捨てるのはBlowfishだけではなく、実際よりも安全だと人々に誤解させます。ここだ8文字の制限の興味深い歴史が。
DOK 2013年

2
72文字の切り捨てはBlowfishアルゴリズムの基本ですか、それともPHPの実装だけですか?IIRC Blowfishは(少なくとも一部の)nixでもユーザーパスワードを暗号化するために使用されます。
ダグラスB.ステープル

3
問題はBlowfishではなくBcryptにあります。この問題はPythonとBcryptだけで再現できます。
Blender 2013年

@ブレンダー:あなたのコメントとあなたの仕事に感謝します。phpでふぐとbcryptの異なる関数を見つけることができませんでした。しかし、それは私にとってphpで何か違いを生まないのですか?標準のphp関数を使用したいと思います。
フレデリクカマー2013年

1
OpenwallのPHPパスワードハッシュフレームワーク(PHPass)もご覧ください。その移植性があり、ユーザーパスワードに対する多くの一般的な攻撃に対して強化されています。フレームワーク(SolarDesigner)を書いた人は、John The Ripperを書いた人と同じで、パスワードハッシュコンテストの審査員を務めています。したがって、彼はパスワードへの攻撃について少し知っています。
jww 2014年

回答:


134

ここでの問題は基本的にエントロピーの問題です。そこで、そこから見ていきましょう。

文字あたりのエントロピー

バイトあたりのエントロピーのビット数は次のとおりです。

  • 16進文字
    • ビット:4
    • 値:16
    • 72文字のエントロピー:288ビット
  • 英数字
    • ビット:6
    • 値:62
    • 72文字のエントロピー:432ビット
  • 「共通」の記号
    • ビット:6.5
    • 値:94
    • 72文字のエントロピー:468ビット
  • 全バイト
    • ビット:8
    • 値:255
    • 72文字のエントロピー:576ビット

したがって、どのように行動するかは、予想される文字のタイプによって異なります。

最初の問題

コードの最初の問題は、「ペッパー」ハッシュステップが16進文字を出力することです(4番目のパラメーターhash_hmac()が設定されていないため)。

したがって、コショウをハッシュすることで、パスワードに使用できる最大エントロピーを2倍(576から288 可能なビット)に効果的に削減できます。

第二の問題

ただし、そもそもエントロピーのビットをsha256提供するだけ256です。つまり、可能な576ビットを256ビットに効果的に削減しています。ハッシュステップは、*すぐに*、定義により、パスワードの可能なエントロピーの少なくとも 50%を失い ます。

これを部分的に解決するには、に切り替えSHA512ます。使用可能なエントロピーは約12%しか減少しません。しかし、それはまだ重要な違いではありません。その12%は、順列の数をの係数で減らし1.8e19ます。それは大きな数字です...そしてそれがそれを減らす要因です...

根本的な問題

根本的な問題は、72文字を超える3種類のパスワードがあることです。このスタイルシステムがそれらに与える影響は大きく異なります。

注:ここからはSHA512、生の出力(16進数ではない)を使用するペッパーシステムと比較していると仮定します。

  • 高エントロピーランダムパスワード

    これらのユーザーは、パスワードジェネレーターを使用して、パスワード用の大きなキーを生成します。それらはランダムで(人間が選択したものではなく)生成され、キャラクターごとに高いエントロピーを持っています。これらのタイプは、ハイバイト(文字> 127)といくつかの制御文字を使用しています。

    このグループの場合、ハッシュ関数は使用可能なエントロピーをに大幅に減らしますbcrypt

    もう一度言いましょう。エントロピーが高く、長いパスワードを使用しているユーザーの場合、このソリューションは、パスワードの強度を測定可能な量だけ大幅に減らします。(72文字のパスワードでは62ビットのエントロピーが失われ、長いパスワードではさらに多くなります)

  • 中程度のエントロピーのランダムパスワード

    このグループは、一般的な記号を含むパスワードを使用していますが、上位バイトや制御文字は使用していません。これらは、入力可能なパスワードです。

    このグループでは、より多くのエントロピーを少しアンロックします(それを作成するのではなく、より多くのエントロピーをbcryptパスワードに合わせることができます)。少し言うときは少し意味します。損益分岐は、SHA512が持つ512ビットを最大にすると発生します。したがって、ピークは78文字です。

    もう一度言いましょう。このクラスのパスワードの場合、エントロピーが不足するまでは、追加の6文字しか保存できません。

  • 低エントロピーのランダムでないパスワード

    これは、おそらくランダムに生成されない英数字を使用しているグループです。聖書の引用のようなもの。これらのフレーズには、1文字あたり約2.3ビットのエントロピーがあります。

    このグループの場合は、ハッシュすることで、エントロピーを大幅に解放できます(作成するのではなく、bcryptパスワード入力にさらに適合させることができます)。エントロピーがなくなる前の損益分岐点は約223文字です。

    もう一度言いましょう。このクラスのパスワードの場合、事前ハッシュによりセキュリティが大幅に向上します。

現実世界に戻る

これらの種類のエントロピー計算は、現実の世界ではそれほど重要ではありません。重要なのは、エントロピーを推測することです。これが、攻撃者が実行できる操作に直接影響します。それが最大化したいものです。

エントロピーを推測する研究はほとんどありませんが、指摘したい点がいくつかあります。

連続して72個の正しい文字をランダムに推測する可能性は非常に低いです。この衝突をするよりも、パワーボール宝くじに21回勝つ可能性が高くなります...それは、私たちが話している数字の中でどれほど大きいかです。

しかし、統計的にそれでつまずかないかもしれません。フレーズの場合、最初の72文字が同じになる確率は、ランダムパスワードの場合よりもはるかに高くなります。しかし、それでもごくわずかです(1文字あたり2.3ビットに基づいて、パワーボール宝くじに5回当たる可能性が高くなります)。

実質的に

実際には、それは重要ではありません。誰かが最初の72文字を正しく推測する可能性は非常に低いので、心配する必要はありません。どうして?

さて、あなたはフレーズを取っているとしましょう。人が最初の72文字を正しく取得できる場合、それらは本当にラッキーである(そうではない)か、一般的なフレーズです。それが一般的なフレーズである場合、唯一の変数はそれを作る時間です。

例を見てみましょう。聖書から引用してみましょう(他の理由ではなく、長いテキストの一般的な情報源だからです):

あなたはあなたの隣人の家を切望してはならない。あなたはあなたの隣人の妻、または彼のしもべまたは女中、彼の牛またはロバ、またはあなたの隣人に属するものを欲しがってはなりません。

それは180文字です。73番目の文字はg2番目のneighbor'sです。それほど多くを推測した場合は、おそらくで停止するのでneiはなく、残りの節を続けます(これが、パスワードが使用される可能性が高いためです)。したがって、「ハッシュ」はあまり追加されませんでした。

ところで、私は絶対に聖書の引用を使用することを主張していません。実際、正反対です。

結論

最初にハッシュすることによって長いパスワードを使用する多くの人を本当に助けるつもりはありません。あなたが間違いなく助けることができるいくつかのグループ。あなたが間違いなく傷つけることができるいくつか。

しかし結局のところ、それはあまり重要ではありません。私たちが扱っている数字は、単にあるWAY高すぎます。エントロピーの違いはそれほど大きくありません。

bcryptはそのままにしておく方がよいでしょう。防止しようとしている攻撃が発生するよりも、ハッシュを台無しにする可能性が高くなります(文字通り、既に実行済みであり、その間違いを犯したのは最初でも最後でもありません)。

サイトの残りの部分を保護することに焦点を当てます。登録時にパスワードボックスにパスワードエントロピーメーターを追加して、パスワードの強度を示します(パスワードが長すぎて、ユーザーが変更したい場合があることを示します)...

それは少なくとも私の$ 0.02(またはおそらく$ 0.02よりはるかに多い)...

「シークレット」ペッパーを使用する限り:

文字通り、1つのハッシュ関数をbcryptにフィードする研究はありません。したがって、「ペッパー」ハッシュをbcryptにフィードすることで未知の脆弱性が発生するかどうかは、よく分からないだけです(実行hash1(hash2($value))すると、衝突耐性とプリイメージ攻撃に関する重大な脆弱性が公開される可能性があることがわかっています)。

秘密鍵(「ペッパー」)の保存をすでに検討していることを考えると、よく研究され理解されている方法でそれを使用しないのはなぜですか。保存する前にハッシュを暗号化しないのはなぜですか?

基本的に、パスワードをハッシュした後、ハッシュ出力全体を強力な暗号化アルゴリズムにフィードします。次に、暗号化された結果を保存します。

現在、SQLインジェクション攻撃は暗号鍵を持たないため、有用な情報を漏らすことはありません。そして、キーが漏えいした場合、攻撃者はプレーンハッシュを使用した場合と同じです(これは証明可能ですが、「プリハッシュ」のペッパーでは提供されません)。

注:これを行う場合は、ライブラリを使用してください。PHPの場合、Zend Framework 2のパッケージを強くお勧めしZend\Cryptます。この時点で私が実際にお勧めするのはこれだけです。それは強く見直され、それはあなたのためにすべての決定をします(これはとても良いことです)...

何かのようなもの:

use Zend\Crypt\BlockCipher;

public function createHash($password) {
    $hash = password_hash($password, PASSWORD_BCRYPT, ["cost"=>$this->cost]);

    $blockCipher = BlockCipher::factory('mcrypt', array('algo' => 'aes'));
    $blockCipher->setKey($this->key);
    return $blockCipher->encrypt($hash);
}

public function verifyHash($password, $hash) {
    $blockCipher = BlockCipher::factory('mcrypt', array('algo' => 'aes'));
    $blockCipher->setKey($this->key);
    $hash = $blockCipher->decrypt($hash);

    return password_verify($password, $hash);
}

また、すべてのアルゴリズムをよく理解され、十分に研究された方法で使用しているため、これは有益です(少なくとも比較的)。覚えておいてください:

最も無知なアマチュアから最高の暗号学者まで、誰でも彼自身が破ることができないアルゴリズムを作成できます。


6
この詳細な回答をありがとうございました。これは本当に私に役立ちます!
Frederik Kammer

1
この答えに対する私の褒め言葉。しかし、ほんの少しだけ簡単に言えば、辞書の中に含まれている非常に弱いパスワード、単語、および派生物を使用してパスワードを解読するのは大多数のユーザーであり、コショウはエントロフィの質問から独立して保護します。エントロピーが失われないようにするには、パスワードとペッパーを連結するだけです。ただし、ハッシュ値の暗号化に関する提案は、サーバー側のシークレットを追加するためのおそらく最良の解決策です。
martinstoeckli 2013年

2
@martinstoeckli:コショウの概念に関する私の問題は、その価値ではありません。「ペッパー」のアプリケーションが暗号化アルゴリズムの観点から未知の領域に入るということです。それは良いことではありません。代わりに、暗号プリミティブは、それらが一緒に機能するように設計された方法で組み合わせる必要があると思います。基本的に、暗号について何も知らない人が「もっとハッシュは良いです!私たちは塩を持っています、コショウもいいです!」。私はむしろ、より単純で、よりテストされた、より単純な
実装を望んでいます

@ircmaxell-はい、ハッシュ値が後で暗号化される限り、私はあなたの見解を知っており、同意します。この追加の手順を実行しない場合、辞書攻撃は、優れたハッシュアルゴリズムを使用していても、脆弱なパスワードが多すぎることを明らかにするだけです。
martinstoeckli 2013年

@martinstoeckli:私はそこに同意しません。秘密を保存することは簡単なことではありません。代わりに、良いコストでbcryptを使用する場合(今日12)、最も弱いクラスのパスワードを除くすべてが安全です(辞書であり、簡単なパスワードは弱いものです)。そのため、強度メーターを使用してユーザーを教育し、そもそもより良いパスワードを使用できるようにすることに重点を置くことをお勧めします...
ircmaxell

5

パスワードをペペリングすることは確かに良いことですが、その理由を見てみましょう。

まず、まさにコショウが役立つときの質問に答えるべきです。コショウはパスワードが秘密のままである限りパスワードを保護するだけなので、攻撃者がサーバー自体にアクセスできる場合、それは役に立ちません。はるかに簡単な攻撃ですが、SQLインジェクションです。これにより、データベース(ハッシュ値への)への読み取りアクセスが可能になります。SQLインジェクションのデモを準備して、それがいかに簡単かを示します(次の矢印をクリックして準備します)入力)。

次に、コショウは実際に何を助けますか?コショウが秘密のままである限り、それは辞書攻撃から弱いパスワードを保護します。パスワード1234は次のようになります1234-p*deDIUZeRweretWy+.O。このパスワードは非常に長くなるだけでなく、特殊文字も含まれているため、辞書の一部にはなりません。

ユーザーが使用するパスワードを推定できるようになりました。64〜72文字のパスワードを持つユーザーがいるため(実際にはこれは非常にまれです)、弱いパスワードを入力するユーザーが増える可能性があります。

もう1つのポイントは、総当たり攻撃の範囲です。sha256ハッシュ関数は、256ビットの出力または1.2E77の組み合わせを返します。これは、GPUの場合でも、総当り攻撃には多すぎます(正しく計算された場合、2013年のGPUで約2E61年必要です)。だからコショウを塗っても本当の不利はありません。ハッシュ値は体系的ではないため、一般的なパターンで総当たりを高速化することはできません。

PS私が知る限り、72文字の制限はBCrypt自体のアルゴリズムに固有です。私が見つけた最良の答えはこれです。

PPS私はあなたの例に欠陥があると思います、あなたは完全なパスワード長でハッシュを生成することができず、それを切り詰めたもので検証することができません。おそらく、ハッシュを生成したり、ハッシュを検証したりするために同じ方法でペッパーを適用するつもりでした。


あなたのPPSに関して、私はただ言うことができます:はい、彼は切り捨てられていないパスワードのハッシュで切り捨てられたパスワードを検証し、それでも取得できtrueます。それがこの質問のすべてです。自分で見てください:viper-7.com/RLKFnB
Sliq

@Panique-問題はBCryptハッシュの計算ではなく、以前のHMACです。SHAハッシュを生成するために、OPは完全なパスワードを使用し、その結果をBCryptの入力として使用します。検証のために、SHAハッシュを計算する前にパスワードを切り捨て、この完全に異なる結果をBCryptの入力として使用します。HMACは任意の長さの入力を受け入れます。
martinstoeckli 2013年

2

Bcryptは、高価なBlowfishキーセットアップアルゴリズムに基づくアルゴリズムを使用します。

bcryptに推奨される56バイトのパスワード制限(ヌル終了バイトを含む)は、Blowfishキーの448ビット制限に関連しています。この制限を超えるバイトは、結果のハッシュに完全には混合されません。したがって、bcryptパスワードの72バイトの絶対制限は、それらのバイトによる結果のハッシュへの実際の影響を考慮すると、それほど重要ではありません。

ユーザーが通常55バイトを超える長さのパスワードを選択すると思われる場合は、代わりにいつでもパスワードストレッチのラウンドを増やして、パスワードテーブル違反の場合のセキュリティを高めることができることを覚えておいてください(ただし、これは追加の文字)。ユーザーのアクセス権が非常に重要で、ユーザーが通常は非常に長いパスワードを必要とする場合、パスワードの有効期限も2週間のように短くする必要があります。つまり、ハッカーが各トライアルパスワードをテストして、一致するハッシュを生成するかどうかを確認するために必要な作業要素を打ち負かすためにリソースを投資している間、パスワードが有効である可能性ははるかに低くなります。

もちろん、パスワードテーブルが侵害されていない場合、ユーザーのアカウントをロックアウトする前に、ハッカーがユーザーの55バイトのパスワードを推測できるのは最大で10回までです;)

55バイトより長いパスワードを事前にハッシュすることにした場合は、SHA-384を使用する必要があります。これは、制限を超えずに出力が最大になるためです。


1
「非常に長いパスワード」の「パスワードの有効期限も2週間のように短くする必要があります。実際には、パスワードを保存する必要がなく、毎回パスワードをリセットするだけです。真剣に、それは間違った解決策です、トークンによる二要素認証に移ります。
zaph 2017

@zaphに感謝します。その例を教えてもらえますか?それは面白そう。
Phil

[DRAFT NIST Special Publication 800-63B Digital Authentication Guideline](pages.nist.gov/800-63-3/sp800-63b.html)、5.1.1.2。記憶された秘密の検証:検証者は、記憶された秘密を任意に(たとえば、定期的に)変更することを要求してはなりません(SHOULD NOT)。また、ジム・フェントンによるパスワード要件の改善に向けてを参照しください。
zaph 2017

1
問題は、ユーザーがパスワードの変更を要求される頻度が高くなるほど、パスワードの選択肢が最悪になり、セキュリティが低下することです。ユーザーは覚えやすいパスワードが限られているため、
使い果たさ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.