web-dev-qa-db-ja.com

塩とコショウを使用しながら、現在の「承認済み」、「実証済み」、およびメモリ/ CPUの高価なアルゴリズムを利用するためのより良い方法はありますか?

私はこれらの2つの質問で提示された概念について読みました:

パスワードの長さの制限を避けるためにbcryptを適用する前にパスワードを事前にハッシュする

BcryptとPBKDF2を一緒に使用するのは理にかなっていますか?

私は、両方の質問で提示された概念を組み合わせた実装を思いついたと思いますが、場合によってはいくつかのセキュリティ層を提供します。

質問

  1. この実装は、他のほとんどの実装と比較して比較的安全ですか?
  2. このように複数の機能を連鎖させて足を撃ったことはありますか?
  3. 現在の「承認済み」、「実証済み」、およびメモリを大量に消費するアルゴリズムを利用するためのより良い方法はありますか?
  4. この実装をどのように改善できますか?
  5. 塩とコショウの値が十分に大きいため、より多くのメモリや処理が必要になるため、ハッシュのクラッキングがより困難になるポイントはありますか?

懸念事項

  1. 中間者攻撃
    • SSLStrip
    • ARPスプーフィング、DNSハイジャック、およびHTTPプロキシとしての機能
      • 攻撃者側でSSL接続を終了し、HTTPトラフィックをユーザーに送信する
  2. サーバーコードで処理されるプレーンテキストのパスワード
  3. レインボーテーブルと誕生日の問題
  4. 証明されていないアルゴリズム
  5. ハッシュの迅速かつ効率的な計算
  6. 本当に長い資格情報
  7. 適切なエントロピーの欠如
  8. 認証データベースのダンプにより、塩とコショウが開示されます
  9. 電子メールのプレーンテキストストレージ

ソリューション

  1. プレーンテキストのパスワードをネットワーク経由で送信しないでください。SSLはサイト全体でのみ使用してください。
  2. サーバーに送信する前に、パスワードをソルトしてハッシュします
  3. ユーザー独自のペッパーがサーバーに適用されます
  4. ハッシュチェーンは、RSAによって精査されたアルゴリズムであるPBKDF2で終了します
  5. ハッシュチェーンは4kBのメモリを必要とするため、bcryptを利用します
  6. Bcryptへの入力文字列はSHA-512でハッシュされ、入力文字数が最大値を下回ります。
  7. 塩とコショウは長く、ランダムな文字列になります
  8. 内部APIからのみアクセス可能な別のサービスにプライベートソルトとペッパーを保存する
  9. パブリックトラフィックを処理するサーバーにメールアドレスとパスワードのハッシュを保存します

コンポーネント

アルゴリズム

SHA-512, bcrypt, PBKDF2

パブリックソルト

public_salt

プライベートペッパー

email_pepper, bcrypt_pepper, pbkdf2_pepper

ユーザーグローバル

public_salt, email_pepper

ユーザー固有

bcrypt_pepper, pbkdf2_pepper

処理する

  1. ユーザーはウェブフォームにメールアドレスとパスワードを入力し、それらを送信してログインします。
  2. 電子メールアドレスとパスワード文字列は、public_saltでPBKDF2を使用して(個別に)ハッシュされ、結果として得られる2つの1024ビットキー(email_key、password_key)がSSLを介してサーバーにPOSTされます。
  3. サーバーは、stored_email_keyを取得するために、より高い反復回数のemail_pepperを使用して、PBKDF2でemail_keyを再度ハッシュします。
  4. 次に、サーバーは内部専用サービスにクエリを実行して、stored_email_keyの保存された一意のペッパーを要求し、bcrypt_pepperとpbkdf2_pepperを受信します。
  5. password_keyはSHA-512を使用してハッシュされ、キーの長さが短縮されるため、bcryptは入力を切り捨てず、結果としてreduced_hashになります。
  6. 次に、reduced_hashはbcryptとbcrypt_pepperを使用してハッシュされ、bcrypt_hashになります。
  7. 次に、pBKDF2とpbkdf2_pepperを使用してbcrypt_hashがハッシュされ、最終的に保存されたパスワードハッシュが生成されます。

概要概要

email_key = PBKDF2(email, public_salt)
password_key = PBKDF2(password, public_salt)
POST: keys -> SSL -> server
stored_email_key = PBKDF2(email_key, email_pepper)
server gets bcrypt_pepper, and pbkdf2_pepper
reduced_hash = SHA-512(password_key)
bcrypt_hash = bcrypt(reduced_hash, bcrypt_pepper)
pbkdf2_hash = PBKDF2(bcrypt_hash, pbkdf2_pepper)

複利

Password - pbkdf2(bcrypt(sha512(pbkdf2(password, public_salt)), bcrypt_pepper), pbkdf2_pepper)
Email address - pbkdf2(pbkdf2(email_address, public_salt), email_pepper)

メールアドレスの保存について

  1. メールアドレスは、通知、パスワードのリセット、ニュースレターにのみ必要です。
  2. 電子メールアドレスは、パブリックトラフィックを処理するシステムまたはクラスターにPBKDF2ハッシュとして保存されます。
  3. 電子メールアドレスは、受信者に電子メールを送信する必要がある内部コードのみが利用できるAPIを介してアクセス可能なサービスに暗号化されて保存されます。

これはやり過ぎかもしれませんが、パスワードとメールアドレスが適切に処理および保存されていることを確認したいと思います。

詳細

プロセスの各ステップの反復回数にどの値を使用するかについては、まだ議論中です。明らかに、私はjavascriptよりもサーバー上でより多くの反復を使用するつもりです。

PBKDF2を使用する1024ビットのキーを生成することと、2048ビット以上のソルトを使用することを考えています。

3
clay richardson

セキュリティの最初のルールは次のとおりです:独自の暗号をロールしないでください

あなたは複雑なスキーマを思いついたが、それはベストプラクティスよりも実際には何も改善しない。また、ソルトやペッパーとは何か、なぜそれらが使用されるのかについてもわかりません。ソルトは固定長のバイトのランダムなセットであり、秘密とは見なされません。コショウは(秘密の)鍵です。

クライアント側のハッシュ
クライアント側で値をハッシュしても、次の理由で何も得られません。

  1. すでにSSLを使用しているため、ネットワーク経由で送信する前にすべてが暗号化されます
  2. クライアント側でパスワードなどをハッシュすると、パスワードのハッシュが事実上パスワードになります。

メールアドレス
ユーザーと通信するために後で必要になるため、通常はユーザーのメールアドレスをリバーシブル/読み取り可能な形式にする必要があります。派生値しかない場合は、連絡できません。

事前にハッシュされたパスワード
BCryptは、パスワードを55バイトの入力に切り捨てます( salt を除く)。一般的に引用されている128ビット、256ビット、さらには1024ビットの値を考慮すると、55バイトはそれほど多くないように思われるかもしれません。ただし、一般的なパスワードは、6〜10文字の範囲の長さの現実です。

より長い値を許可したい場合は、単に使用します

bcrypt(sha512($password));*

コショウの値はここで議論されています の必要性。コショウとソルトの両方を使用してパスワードを保存する場合は、次を使用します。

bcrypt(hash_hmac('sha256', $password, $pepper));*

推奨されるように ここ

*)どちらの例でも、ソルトを自動的に作成するBCrypt実装を使用していると想定しています。

4
Jacco