web-dev-qa-db-ja.com

ベストプラクティス:パスワードを塩漬けにしますか?

私がやっていることは、実際にはパスワードを塩漬けするのではなく、それらをペッパーにすることであるということを学んだ議論に出会いました。

hash_function($salt.hash_function($pepper.$password)) [multiple iterations]

選択したハッシュアルゴリズムを無視します(これは特定のアルゴリズムではなく、塩と胡pepperの議論になりたいが、安全なアルゴリズムを使用しています)、これは安全なオプションですか、何か違うことをすべきですか?用語に不慣れな人のために:

  • saltは、ハッシュテーブルを使用してパスワードをクラックすることを不可能にするように設計されたデータベース内の文字列とともに通常格納されるランダムに生成された値です。各パスワードには独自のソルトがあるため、それらをクラックするにはすべて個別にブルートフォースする必要があります。ただし、ソルトはパスワードハッシュとともにデータベースに格納されるため、データベースの侵害は両方を失うことを意味します。

  • pepperは、データベースとは別に保存されるサイト全体の静的な値であり(通常、アプリケーションのソースコードにハードコードされます)、秘密にすることを目的としています。データベースのセキュリティが侵害されても、アプリケーションのパスワードテーブル全体が総当たり攻撃にならないようにするために使用されます。

不足しているものはありますか?ユーザーのセキュリティを保護するために、パスワードに塩漬けとペッパーをかけるのが最善の選択肢ですか?この方法でセキュリティ上の問題が発生する可能性はありますか?

注:議論の目的で、アプリケーションとデータベースは別々のマシンに保存され、パスワードなどを共有しないと仮定します。そのため、データベースサーバーの違反は自動的に違反を意味しません。アプリケーションサーバー

137
Glitch Desire

OK。これについて over および over について書く必要があるので、コショウだけで最後の標準的な答えを1つ行います。

唐辛子の見かけ上の逆さま

唐辛子はハッシュ関数をより安全にする必要があることは非常に明らかです。つまり、攻撃者がデータベースを取得するだけであれば、ユーザーのパスワードは安全なはずですよね?論理的ですね。

だからこそ、多くの人々が唐辛子は良い考えだと信じています。それは理にかなっている"。

ペッパーズの現実

セキュリティおよび暗号化の領域では、「意味をなす」だけでは十分ではありません。安全であると見なされるためには、証明可能なものおよびが必要です。さらに、保守可能な方法で実装可能でなければなりません。維持できない最も安全なシステムは、安全でないと見なされます(そのセキュリティの一部が故障すると、システム全体が崩壊するため)。

そして、唐辛子は証明可能なモデルにも保守可能なモデルにも適合しません...

ペッパーの理論的問題

ステージを設定したので、ピーマンの何が問題なのか見てみましょう。

  • あるハッシュを別のハッシュにフィードすることは危険です。

    この例では、hash_function($salt . hash_function($pepper . $password))を実行します。

    過去の経験から、1つのハッシュ結果を別のハッシュ関数に「フィードする」だけで、全体的なセキュリティが低下することがあります。その理由は、両方のハッシュ関数が攻撃の標的になる可能性があるためです。

    PBKDF2 のようなアルゴリズムが特別な操作を使用してそれらを結合するのはそのためです(その場合はhmac)。

    重要なことは、大したことではないが、ただ投げるのは簡単なことでもないということです。暗号システムは、「動作するはず」のケースを回避するように設計されており、代わりに「動作するように設計された」ケースに焦点を当てています。

    これは純粋に理論的に見えるかもしれませんが、実際にはそうではありません。たとえば、 Bcryptは任意のパスワードを受け入れることはできません 。したがって、bcrypt(hash(pw), salt)を渡すと、bcrypt(pw, salt)がバイナリ文字列を返す場合、hash()よりもはるかに弱いハッシュになることがあります。

  • デザインに対する取り組み

    Bcrypt(および他のパスワードハッシュアルゴリズム)の設計方法は、ソルトを使用することです。コショウの概念は導入されませんでした。これは些細なことのように思えるかもしれませんが、そうではありません。その理由は、塩は秘密ではないからです。これは、攻撃者が知ることができる値にすぎません。一方、唐辛子は、まさに定義上、暗号の秘密です。

    現在のパスワードハッシュアルゴリズム(bcrypt、pbkdf2など)はすべて、1つの秘密値(パスワード)のみを取り込むように設計されています。アルゴリズムに別の秘密を追加することは、まったく研究されていません。

    それは安全ではないという意味ではありません。安全かどうかわからないということです。また、セキュリティと暗号化に関する一般的な推奨事項は、わからない場合は知らないということです。

    そのため、秘密の値(ペッパー)で使用するために暗号作成者によってアルゴリズムが設計および検証されるまで、現在のアルゴリズムをそれらで使用しないでください。

  • 複雑さはセキュリティの敵です

    信じられないかもしれませんが、 複雑さはセキュリティの敵です 。複雑に見えるアルゴリズムを作成することは安全かもしれませんし、そうでないかもしれません。しかし、安全でない可能性は非常に重要です。

ペッパーの重大な問題

  • メンテナンス不可です

    唐辛子を実装すると、唐辛子キーを回転させることができなくなります。コショウは一方向関数への入力で使用されるため、値の有効期間中はコショウを変更することはできません。これは、キーローテーションをサポートするためにいくつかの不安定なハックを考え出す必要があることを意味します。

    これは非常に重要です暗号の秘密を保存するときは常に必要です。キーをローテーションするメカニズムがない(定期的に、および侵害後に)ことは、大きなセキュリティ上の脆弱性です。

    そして、あなたの現在の唐辛子のアプローチでは、すべてのユーザーがローテーションによってパスワードを完全に無効にするか、次のログインがローテーションするまで待つ必要があります(これは決してないかもしれません)...

    これは基本的に、あなたのアプローチを即座に立ち入り禁止にします。

  • 独自の暗号をローリングする必要があります

    現在のアルゴリズムはコショウの概念をサポートしていないため、アルゴリズムを構成するか、コショウをサポートする新しいアルゴリズムを発明する必要があります。そして、なぜそれが本当に悪いことなのかすぐに理解できない場合:

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

    NEVER独自の暗号をロール...

より良い方法

したがって、上記で詳述したすべての問題のうち、状況を処理する方法は2つあります。

  • アルゴリズムをそのまま使用する

    Bcryptまたはscryptを正しく(高コストで)使用する場合、最も弱い辞書パスワード以外はすべて統計的に安全です。コスト5でbcryptをハッシュするための現在のレコードは、1秒あたり71kハッシュです。そのレートでは、6文字のランダムなパスワードでさえクラックするのに何年もかかります。また、最小推奨コストを10と考えると、1秒あたりのハッシュが32分の1に削減されます。したがって、1秒あたり約2200のハッシュしか話せません。そのレートでは、一部の辞書句や修正でも安全です。

    さらに、ドアでそれらの弱いクラスのパスワードをチェックし、許可しないようにする必要があります。パスワードのクラッキングがより高度になるにつれて、パスワードの品質要件も同様になります。まだ統計的なゲームですが、適切なストレージ技術と強力なパスワードを使用すれば、誰もが実質的に非常に安全であるはずです...

  • 保存前に出力ハッシュを暗号化する

    セキュリティレルムには、上記のすべてを処理するように設計されたアルゴリズムが存在します。これはブロック暗号です。リバーシブルであるため、キーを回転させることができます(イェー!メンテナンス性!)。設計どおりに使用されているため、優れています。ユーザーに情報を提供しないので、それは良いことです。

    もう一度その行を見てみましょう。攻撃者があなたのアルゴリズムを知っているとしましょう(これはセキュリティに必要です。それ以外の場合は、あいまいさによるセキュリティです)。従来のペッパーアプローチでは、攻撃者はセンチネルパスワードを作成できます。また、彼は塩と出力を知っているため、ペッパーをブルートフォースできます。 OK、それはロングショットですが、それは可能です。暗号を使用すると、攻撃者は何も取得しません。また、ソルトはランダム化されているため、センチネルパスワードは役に立たないでしょう。残された最善の方法は、暗号化されたフォームを攻撃することです。つまり、暗号化キーを回復するには、まず暗号化されたハッシュを攻撃し、次にハッシュを攻撃する必要があります。しかし、暗号の攻撃に関するlotの研究があるので、それに頼りたいです。

TL/DR

コショウを使用しないでください。それらには多くの問題があり、2つのより良い方法があります。サーバー側のシークレットを使用しない(はい、大丈夫です)と、ストレージの前にブロック暗号を使用して出力ハッシュを暗号化します。

295
ircmaxell

コショウの正確な利点

  • ペッパーは辞書攻撃から弱いパスワードを保護できます。特別な場合、攻撃者はデータベース(ハッシュを含む)に読み取りアクセスできますが、ペッパーのソースコードにはアクセスできません。

典型的なシナリオは、SQLインジェクション、バックアップの破棄、サーバーの破棄などです。これらの状況は、見た目ほど珍しくはなく、多くの場合、管理下にありません(サーバーホスティング)。使用する場合...

  • パスワードごとに一意のソルト
  • BCryptのような遅いハッシュアルゴリズム

...強力なパスワードは十分に保護されています。塩が知られている場合でも、これらの条件下で強力なパスワードをブルートフォースすることはほぼ不可能です。問題は、ブルートフォース辞書の一部であるか、それらの派生物である弱いパスワードです。最も一般的なパスワードのみをテストするため、辞書攻撃はそれらを非常に高速に明らかにします。

2番目の質問はコショウの塗り方ですか?

ペッパーを適用するためによく推奨される方法は、パスワードとペッパーを組み合わせてからハッシュ関数に渡すことです。

$pepperedPassword = hash_hmac('sha512', $password, $pepper);
$passwordHash = bcrypt($pepperedPassword);

しかし、さらに良い方法があります:

$passwordHash = bcrypt($password);
$encryptedHash = encrypt($passwordHash, $serverSideKey);

これにより、サーバー側のシークレットを追加できるだけでなく、必要に応じて$ serverSideKeyを交換することもできます。この方法にはもう少し手間がかかりますが、コードが一度存在する場合(ライブラリー)、使用しない理由はありません。

23
martinstoeckli

塩コショウのポイントは、Rainbowテーブルと呼ばれる、事前に計算されたパスワード検索のコストを増やすことです。

一般に、単一のハッシュの衝突を見つけることは困難です(ハッシュが安全であると仮定)。ただし、短いハッシュでは、コンピューターを使用して、考えられるすべてのハッシュを生成してハードディスクを検索することができます。これは、レインボーテーブルと呼ばれます。レインボーテーブルを作成すると、世界中に出て、任意の(塩漬けされていない)ハッシュのもっともらしいパスワードをすばやく見つけることができます。

コショウのポイントは、パスワードリストをハックするために必要なRainbowテーブルを一意にすることです。したがって、攻撃者がレインボーテーブルを構築するためにより多くの時間を浪費します。

ただし、ソルトのポイントは、各ユーザーのレインボーテーブルをそのユーザーに固有のものにし、攻撃の複雑さをさらに高めることです。

本当にコンピューターセキュリティのポイントは、数学的にも物理的にも実用的ではなく、(数学的に)不可能にすることではありません(たとえば、セキュリティで保護されたシステムでは、単一のユーザーのパスワードを計算するために宇宙(およびその他)のすべてのエントロピーが必要になります)。

2
Aron

ソースコードにハードコードされた値を保存することは、セキュリティに関連しているとは見なされません。あいまいさによるセキュリティです。

ハッカーがデータベースを取得すると、ユーザーパスワードをブルートフォースするようになります。そのハッカーがいくつかのパスワードを解読できたとしても、そのハッカーがあなたの唐辛子を特定するのに長い時間はかかりません。

1
Sven