ご注意ください:安全なパスワードストレージハッシュの適切な方法は、scryptまたはbcryptのいずれかであることを認識しています。この質問は、実際のソフトウェアでの実装に関するものではなく、私自身の理解によるものです。
関連
背景
私の知る限り、パスワード検証を保存するための推奨/承認された方法は、次のものを保存することです:
_$verifier = $salt + hash( $salt + $password )
_
どこ:
hash()
は暗号ハッシュアルゴリズムです$salt
_は、ランダムな、均等に分散された高いエントロピー値です$password
_は、ユーザーが入力したパスワードです秘密鍵をミックスに追加することを勧める人もいます(pepperと呼ばれることもあります)。コショウが秘密で、高いエントロピー、システム固有の定数である場合。
その理由は、攻撃者がパスワード検証を手に入れても、ペッパーの値を知らない可能性が高いということです。したがって、攻撃を成功させることは困難になります。
だから、私の質問は:
パスワードのハッシュ時にソルトに加えてペッパー値を追加すると、全体的なセキュリティが向上しますか?
それとも、誤った仮定に基づいて認識されたセキュリティの向上ですか?
クイックアップデート
私は_$salt
_の目的を知っています(StackOverflowでかなり 長い答え と書きました)追加の_$pepper
_キーはない塩が何をするかを改善する。
問題は、_$pepper
_は、saltが行う以外のセキュリティ以外を追加しますか?
状況によっては、ピーマンが役立つ場合があります。
典型的な例として、Webアプリケーションを構築しているとします。これは、webappコード(一部のwebappフレームワーク、ASP.NET MVC、 PythonのPyramid、重要ではありません)、ストレージ用のSQLデータベース。 webappとSQL DBは異なる物理サーバーで実行されます。
データベースに対する最も一般的な攻撃は、成功したSQLインジェクション攻撃です。この種類の攻撃は、webappが別のサーバーとユーザーIDで実行されるため、必ずしもwebappコードにアクセスできるわけではありません。
パスワードを安全にデータベースに保存し、次の形式で何かを考え出す必要があります。
$hashed_password = hash( $salt . $password )
ここで、$salt
は、$hashed_password
表現と新規または変更されたパスワードごとにランダムに選択されたとともに、データベースにプレーンテキストで格納されます。
すべてのパスワードハッシュ方式の最も重要な側面は、hash
がslow暗号で保護されたハッシュ関数。詳細な背景知識については、 https://security.stackexchange.com/a/31846/10727 を参照してください。
問題は、アプリケーションコードに定数値を追加するのがほとんどゼロであり、アプリケーションコードが通常SQLインジェクション攻撃中に侵害されない場合、以下は上記よりも実質的に優れていますか?
$hashed_password = hash( $pepper . $salt . $password )
ここで、$salt
はデータベースにプレーンテキストで格納され、$pepper
はアプリケーションコード(またはコードが複数のサーバーで使用されている場合、またはソースがパブリックである場合は構成)のプレーンテキストに格納された定数です。
この$pepper
を追加するのは簡単です。コードに定数を作成し、暗号で保護された大きなランダム値(たとえば、/ dev/urandom hexまたはbase64エンコードから32バイト)を入力して、パスワードハッシュでその定数を使用します。関数。既存のユーザーがいる場合は、移行戦略が必要です。たとえば、次のログイン時にパスワードを再ハッシュし、パスワードハッシュ戦略のバージョン番号をハッシュと一緒に保存します。
$pepper
doesを使用すると、パスワードハッシュの強度が増しますif妥協データベースのは、アプリケーションの侵害を意味しません。コショウの知識がなければ、パスワードは完全に安全なままです。パスワード固有のソルトのため、データベース内の2つのパスワードが同じかどうかを確認することもできません。
その理由は、hash($pepper . $salt . $password)
が$pepper
をキーとして、$salt.$password
を入力として擬似ランダム関数を効果的に構築するためです(SHA *、bcrypt、またはscryptを使用したPBKDF2のような正しいhash
候補の場合)。疑似ランダム関数の2つの保証は、秘密鍵の下で出力から入力を推定できないこと、および鍵の知識がないと入力からの出力を推定できないことです。これはハッシュ関数の一方向のプロパティによく似ていますが、違いは、パスワードなどの低いエントロピー値を使用すると、すべての可能な値を効果的に列挙し、パブリックハッシュ関数で画像を計算して、その値を見つけることができるという事実にあります画像はプレ画像と一致します。疑似ランダム関数では、キーなしでは(つまり、コショウなしで)実行できません。キーなしで単一の値の画像を計算することもできないためです。
この設定での$salt
の重要な役割は、長期間にわたってデータベースにアクセスでき、通常は外部からアプリケーションを操作できる場合に役立ちます。 $salt
を使用しない場合、制御するアカウントのパスワードを既知の値$passwordKnown
に設定し、ハッシュを不明なパスワード$passwordSecret
のパスワードと比較できます。 $passwordKnown==$passwordSecret
の場合のみ、hash($pepper . $passwordKnown)==hash($pepper . $passwordSecret)
として、未知のパスワードを任意の選択した値と比較できます(専門性として、私はハッシュ関数の衝突耐性を想定しています)。しかし、saltを使用すると、$salt1 . $passwordKnown == $salt2 . $passwordSecret
と$salt1
と$salt2
が$passwordKnown
と$passwordSecret
に対してランダムに選択された場合にのみhash($pepper . $salt1 . $passwordKnown)==hash($pepper . $salt2 . $passwordSecret)
が得られます。ソルトは決して同じにはならず(256ビットのような十分に大きなランダム値を想定)、したがって、パスワードを互いに比較する必要はありません。
(注:ソルトを使用することは仕事の半分にすぎません。ハッシュ関数を遅くする必要もあります。そのため、単一の低エントロピーパスワードを攻撃することは依然として困難です。通常、低速化は、複数回の反復、またはソルトとパスワードの10000コピー。)
あなたの「コショウ」がすることはそれがハッシュを [〜#〜] mac [〜#〜] に変換することです。ハッシュ関数から適切で安全なMACを作成するのは簡単ではないので、自家製の構造の代わりに [〜#〜] hmac [〜#〜] を使用することをお勧めします(衝突耐性のあるハッシュ関数は、ランダムなOracleと必ずしも区別できないわけではありません。
MACを使用すると、次の意味である程度のセキュリティが得られる可能性があります。おそらく、攻撃者によるデータベースの読み取りアクセスは、実際の問題ではなくなる可能性があります。 MACキー(「ペッパー」)は、機密性の必要性を集中する可能性があります。ただし、これはMACが一方向の関数であることにも依存しています。これは、多くのMAC構成(HMACを含む)から取得できるプロパティですが、暗号的に言えば実際には保証されていません(微妙な点があります)。
「ペッパー」は、再起動に抵抗する方法で安全なストレージを含め、管理する鍵があることを意味します。キーは小さく、RAMに収まりますが、ストレージ要件のため、実際にセキュリティが向上するかどうかは不明です。データベース全体を読み取ることができる攻撃者は、通常、「保護された」ファイルを含むハードディスク全体を読み取ることもできます。キーのサイズが小さいと、いくつかの高度な設定が可能になる場合があります。ブート時に使用され、その後接続されたままにされないスマートカードに格納されているキー。要約すると、ペパリングが努力に値するかどうかは、コンテキストに完全に依存します。複雑さを増すのを避けるために、一般的には反対することをお勧めします。
コショウが本当にできることを指摘したいと思います。
他の人がすでに指摘したように、攻撃者がデータベースのハッシュ値にアクセスできるが、サーバーを制御できないため、ペッパーを追加することは利点にすぎませんペッパーを知らない。これはSQLインジェクションの典型であり、非常に簡単に実行できるため、おそらく最もよく使用される攻撃の1つです。
$hashValue = bcrypt('12345', $cost, $salt);
このパスワードは、遅い鍵導出関数を正しく使用していても、辞書攻撃で簡単に取得できます。最も使用頻度の高いパスワードを辞書に入れ、この脆弱なパスワードで総当たり攻撃を実行します。 (あまりに)多くの場合にパスワードを見つける可能性が非常に高いです。
$hashValue = bcrypt('12345anm8e3M-83*2cQ1mlZaU', $cost, $salt);
コショウを使用すると、脆弱なパスワードが長くなり、特殊文字が含まれるようになり、さらに重要なことに、辞書にないパスワードが見つかります。したがって、コショウが秘密のままである限り、辞書攻撃を防ぐを実行します。この場合、弱いパスワードを保護できます。
編集:
コショウとして使用するよりも、サーバー側のキーを追加するより良い方法があります。コショウを使用すると、攻撃者はキーを取得するためにサーバーで追加の権限を取得する必要があります。最初にハッシュを計算し、その後サーバー側のキーを使用してハッシュを暗号化する(双方向暗号化)ことで得られる同じ利点。これにより、必要なときにいつでも鍵を交換することができます。
$hash = bcrypt($passwort, $salt);
$encryptedHash = encrypt($hash, $serverSideKey);
Unixパスワードのソルトと反復の発明に関する論文( Password Security:A Case History、Morris&Thompson、1978 )も、pepperに相当するものを説明しています。
ユーザーのパスワードの最初の8文字はDESのキーとして使用されます。次に、アルゴリズムを使用して定数を暗号化します。この定数は現時点ではゼロですが、簡単にアクセスでき、インストールに依存させることができます。
使用されているとは聞いていません。他に誰かいますか?
ちなみに、新しいNIST Digital Idendityガイドライン(ドラフト)では、Pepperも使用することを強くお勧めしています。
https://pages.nist.gov/800-63-3/sp800-63b.html#sec5
5.1.1.2記憶された秘密の検証:
...キー付きハッシュ関数(HMAC [FIPS198-1]など)と、ハッシュ済みオーセンティケータ(たとえば、ハードウェアセキュリティモジュール)とは別に格納されたキーを使用して、格納されたハッシュ済みオーセンティケータに対する辞書攻撃にさらに抵抗する必要があります。
このシナリオを考えてみましょう:
SQLインジェクションを使用してWebサイトXに侵入し、パスワードハッシュとソルトを使用してユーザーのリストを取得しようとしています。 WebサイトXもグローバルコショウを使用しているとします。
SQLインジェクションの前に、私が知っているユーザー名とパスワードを使用して、WebサイトXでユーザーを登録するだけで済みます。次に、データベース内の特定のレコードについて、パスワードハッシュ、プレーンテキストのパスワード、ソルト(プレーンテキストとして保存)を確認し、この1つのレコードに基づいてグローバルコショウをクラックすることは、計算上は簡単です。 。
したがって、実際には、唐辛子はごくわずかなオーバーヘッド時間で攻撃者を遅くする方法です。彼らはパスワード+塩+コショウを力ずくで強制する必要はなく、コショウだけを意図しています。
上記は選択された平文攻撃の形式です。攻撃者がアルゴリズム(hash())、出力($ hashed_password)、および入力( "定数" $ salt&$ passwordおよび "変数" $ pepper)の1つを除くすべてを知っている限り、 "xに対して解決"できます。 "線形代数方程式(h = s + p + x == hsp = x)のようですが、もちろん総当たりです。ペッパーをbcryptの制限である56バイト(448ビット)より長くすると、時間コストが増加し、bcryptと同じくらい優れていますが、scryptほど優れていない場合があります。したがって、コショウが十分に長い限り、それは改善です。
サーバーがグローバルコショウ定数をどのように非表示にすることができるかについてはあまり詳しくありませんが、私の考えでは、遅かれ早かれ、サーバーに侵入したハッカーがペッパーの値を取得する方法を理解するでしょう。コショウの値を完全に安全にするには、特別なハードウェアが必要になります。これを行う1つの方法は、サーバーにインストールされているFPGAボードを使用することです。 FPGAには、pepper値を含むハッシュの実行に使用されるコードが含まれ、すべてのハッシュ計算はFPGA内で行われます。 FPGAを使用すると、プログラミングを一方向の機能にすることができます。コショウはプログラムできますが、それを読み取るために送信できる命令はありません。コショウは金庫に閉じ込められた紙の上に保管されます。コショウがランダムに生成された128+ビットの場合、それを決定する実用的な方法はありません。
サーバーハードウェアのコストが増加するため、これがどれほど実用的かはわかりません。