web-dev-qa-db-ja.com

BCryptを使用してパスワードをクライアント側でハッシュする方法

パスワードのBCryptエンコーディングを使用して、MD5ハッシュを使用した古いアプリケーションをSpring Securityに移行しています。新規ユーザー作成ページ、パスワード変更ページ、ログインページのパスワードをネットワークに送信する前にエンコードしたい。

HTTPSで問題を解決できることはわかっていますが、組織のガイドラインに従って、ネットワーク経由で送信する前にパスワードをエンコードするように指示されます。

JavaScriptを使用してパスワードをハッシュ化するための最良の解決策は何でしょうか?

さらに説明すると、私はAESを使用してパスワードを暗号化するためにJCryption APIを使用しているため、ネットワーク経由で送信される値はAES(SHA1(MD5(plain password)))ですMD5Bcryptのみに置き換えます。残りのものは変更されません。このアプローチは「中間者攻撃」に対して機能しますか?

18
Amit

bcryptは、このタイプのクライアント側ハッシングには対応していません

Bcryptの重要な特性は、同じプレーンテキストで2回独立して実行すると、ほとんどの実装で異なるハッシュが生成されることです。これは、2人の異なるユーザーが同じパスワードを持っているかどうかを確認するのを難しくするように設計されたソルトの使用によるものです。

対照的に、ログインフォームは毎回同じデータを受け取る必要があります。結局のところ、ユーザーが今日入力したパスワードが昨日入力したパスワードと同じであることを他にどのように確認しますか?

したがって、毎回differentデータを生成するように設計されたアルゴリズムがあり、データがsame毎回。これはおそらく、アルゴリズムが意図したとおりに使用されていないことを示しています。

理想的なことはbcryptを使用してサーバー上のパスワードをハッシュするです。これがbcryptが設計したものです。プレーンテキストがメモリにないときにユーザーパスワードを保護します。これは、最も一般的な状態です(たとえば、DBダンプでは、正しく実装されていれば、プレーンテキストではなく、ハッシュされたパスワードのみが表示されます)。

個人的には、クライアント側のハッシュにもある程度の価値があると思います。トラフィックを盗聴できる(またはサーバーにアクセスできる)攻撃者からの保護に役立つためです。ただし、クライアント側のハッシュをサーバー側のbcryptと同じくらい安全にする方法はわかりません。そのため、サーバー側のbcryptを引き続き使用する必要があります。

Bcryptクライアント側を使用する必要がある場合は、静的ソルトを使用します

ログインフォームのクライアント側のハッシュにbcryptを使用する予定で、MD5のドロップイン置換にしたい場合は、静的ソルトを使用する必要があります。特に、SHA1を介して渡す場合は、ハッシュされたデータ自体だけでなく、bcryptソルトも破損するためです。

もちろん、これはbcryptのいくつかの設計上の仮定(常にランダムなソルトを使用するなど)を破ります。

私は個人的にはユーザー名をソルトとして使用することをお勧めします(2人の異なるユーザーが同じパスワードを持っているかどうかを見分けるのが難しいため)。しかし、私はこの文脈で塩漬けに関して行われた研究を知りません。

AES(または対称暗号)もここでは役に立たない

AESは対称アルゴリズムであることを忘れないでください。つまり、データを暗号化するにはを暗号化するには同じキーが必要です。

これはあなたにとって何を意味しますか?まあ、あなたはおそらくあなたの暗号化キーをJavaScriptソースに持っています、それはあなたのログインページにアクセスするクライアントに提供されます。 AESは対称暗号であるため、暗号化キー(復号化キーと同じ)は秘密にしておく必要があります。言い換えると、あなたの秘密鍵は世界に知られています-この時点では実質的にセキュリティを提供しません。

代わりに使用する必要があるのはPGPやHTTPSなどの公開鍵暗号です(厳密には、HTTPSはハイブリッドアプローチを使用しています)。真剣に、何らかの理由で組織がSSL証明書の取得を拒否しない限り、HTTPSを使用するです。 PGPはアクティブなMITM攻撃から実際には保護しませんが、少なくとも盗聴から保護することを覚えておいてください。

12
Ethan Kaminski

HTTPSで問題を解決できることはわかっていますが、組織のガイドラインに従って、ネットワーク経由で送信する前にパスワードをエンコードするように指示されます。

これは実際にあなたの状況を定義します。

基本的に、あなたがとにかく使用する必要がある単純な解決策があります(HTTPSを使用します)。これは、HTTPSがないと、アクティブな攻撃者が、パスワードに使用する「エンコーディング」とハッシュに関係なく、認証手順の後に接続をハイジャックできるためです(攻撃者 中間者攻撃 を実行する立場にある人は、ハッシュ関数と暗号化で儀式的にどれだけ踊るかに関係なく成功します)。次に、ばかばかしく、管理上避けられないガイドラインもある。あなたの問題はそれです:どのようにしてあなたは物事を適切に行うことができ、それでも「ガイドライン」に準拠することができますか?

このガイドラインは、いくつかのレベルではほとんど意味がないことに注意してください。 SSLの欠如は、プロトコルをHijackに対して脆弱にするだけではありません。しかし、あらゆる種類の「エンコーディング」は、受動的な攻撃者に対しても何の効果もありません。その理由は、プロトコルが「クライアントが「エンコードされた」パスワードを表示する」である場合、パッシブ盗聴者は単に「エンコードされたパスワード」を見てそれを自分で送信するためです。したがって、この種のエンコードは実際にはセキュリティを向上させません。仕方。暗号化をある種のバーベキューソースとして理解しているため、一部の人々の感触がより安全になります(「どこにでも散りばめるほど、より良いものになります」)。

私が提案しているのは、次のことを行うことです。

  1. まず、「HTTPS」が「エンコーディング」を具体化するというアイデアを売り込もうとします。言い換えると、SSLトンネル内でパスワードを送信することにより、パスワードは正式にエンコードされているため(実際には、encrypted、ガイドラインに既に準拠しています。 ))、残りのデータとともに。

  2. 愚かさの蔓延がより深刻で、一部の監査人(彼をボブと呼ぶことにします)が「エンコーディング」の欠如についてまだ当てはまる場合は、クライアント側で可逆エンコーディングを適用してみてください。例えば。パスワードを送信する前に、 Base64 を適用します。つまり、パスワードが「bobsucks」の場合、送信されるもの(もちろんSSL内)は「Ym9ic3Vja3M =」となり、ボブは後者の文字列がであるため、より幸せになります。明らかにはるかに安全です。

ここで重要な点は、要件が意味をなさないため、ソリューションもあまり意味をなさないということです。

45
Tom Leek

認証なしではセキュリティはありません

さらに説明するために、AESを使用してパスワードを暗号化するためにJCryption APIを使用しているため、ネットワーク経由で送信される値はAES(SHA1(MD5(プレーンパスワード)))であり、MD5をBcryptのみに置き換えます。残りのものは変更されません。 このアプローチは「中間者攻撃」に対しても機能します

いいえ、そうではありません。これを十分に強く表現することはできません。 httpsを使用するように説得できないかもしれません(選択肢がないかもしれません)。安全ではなく、ある程度のセキュリティを提供するというあなたの信念は正しくありません。 TLS/SSLを使用せずに先に進むことを余儀なくされた場合は、少なくともシステムに脆弱性があり、「簡単に回避でき、セキュリティが良い」と説明する必要があることを関係者全員に明確に伝えることができます。ローカルのスターバックスでMITMホットスポットを実行しているスクリプトキディは、ユーザーを偽装し、資格情報やHijackセッションを盗む可能性があるため、高度なスキルや複雑な攻撃を必要とするものではありません。

通信チャネルが安全でない場合、送信するコードがクライアントによって実際に実行されるコードであるとは期待できません。 httpe(暗号化されたhttp)だけでなくhttps(安全なhttp)と呼ばれる理由があります。セキュリティは単なる暗号化以上のものです。認証なしの暗号化通信は無意味です。

考慮すべきいくつかのこと:

  • Httpsがなければ、ユーザーはログインページにいることをどのようにして知るのでしょうか。
  • 暗号化して送信する前に、攻撃者がユーザーに送信したログインページを変更して、クレデンシャルのプレーンテキストコピーを送信していないことをどうやって確認しますか?
  • パスワードの二重ハッシュを暗号化しようとしていますが、暗号化キーを安全に送信するにはどうしますか?

暗号化に加えて独自のカスタム認証を行うとどうなりますか

それほど単純ではありません。安全でないチャネル上で安全なチャネルをブートストラップすることは、ささいな問題ではありません。理論的には、プロトコルネゴシエーション、サーバー認証、公開鍵インフラストラクチャ、鍵交換、暗号化、メッセージの整合性、失効など、httpsのすべての側面を複製するカスタムプロトコルを構築できます(多くの場合、忘れてしまいます)。完了すると、TLSと同じくらい大きく複雑になります。また、どのTLS実装よりも欠陥が少なく、数年以内にそれを実行できたとしても、ほとんど不可能な問題が発生するとします。このクライアント側コンポーネントをどのようにしてクライアントに送信しますか? 「クライアントに安全にダウンロードしてもらいましょう...待ってください」。安全でないチャネルを介して安全な通信をブートストラップすることが簡単に思える場合、正直なところ、十分に深く調べていなかった場合は、カメはずっと下にあります。

ここではっきりさせておきますが、TLSには多くの問題があり、CAシステムにも多くの問題があります。完璧なふりをするつもりはありませんが、安全な通信は鶏と卵の問題であり、私たちの最善のソリューションです。

クライアント側のハッシュはhttpsを介して実行できます

あなたの言い回しから、質問は「クライアント側のハッシュOR https経由のサーバー側のハッシュ」」であると考えているようですが、それが誤りであることがわかると思います。方法に関係なく、httpsが必要ですユーザーを認証します。つまり、httpsが必要であることに同意した場合、質問は、「サーバー側ハッシュ(https経由)の代わりにクライアント側ハッシュ(https経由)を使用することがなぜ、またはなぜ意味があるのですか?ほとんどの場合、クライアント側のハッシュはより複雑で安全ではありませんが、1つの利点があります。つまり、サーバーはパスワードをまったく認識しないため、サーバー側のハッシュには当てはまりません。シナリオによっては、 (サーバー)を拒否できるようにします。所有していないキーを失うことはありません。また、顧客が解読キーを提供していない場合でも、顧客のファイルを解読するように強制することはできません。そのため、シナリオによっては必須の要件かもしれませんが、それは恣意的な決定ではなくプロジェクト設計の一部であるべきです。ゼロナレッジシナリオを処理する方法は、新しい質問として行う方がよいでしょう。

25
Gerald Davis

最善の解決策は、次のとおりです。

HTTPS経由でパスワードを送信する場合、ハッシュ化してもセキュリティは向上しません。

パスワードをプレーンHTTPで送信している場合、攻撃者はハッシュされたパスワードを取得し、それを使用して自分自身にログインすることができます。または、JavaScriptを改ざんして、ハッシュ化する前にパスワードを送信することもできます。どちらの場合も、パスワードのハッシュ化はセキュリティを提供しません。

9
Mark

あなたはこのガイドラインを実装することにコミットしているようですので、私はあなたの質問に直接答えます。ただし、BCryptとMD5は大きく異なることを理解してください。 BCryptは意図的にかなりの作業を行いますが、MD5はかなり少ないので、約束に対処する必要があります。

<!-- https://github.com/nevins-b/javascript-bcrypt -->
<script src='bCrypt.js'></script>
<script src='isaac.js'></script>
<script>
  // ... your code, then:
  var bcrypt = new bCrypt();
  bcrypt.hashpw('plain password', bcrypt.gensalt(), function (hashed) {
      var cipher = AES(SHA1(hashed));
      // now you have your "secure" hash
  });
</script>

他の回答でセージのアドバイスを検討することをお勧めします。このガイドラインが価値を追加するシナリオはまれであるため、自問してください。セキュリティを追加せず、ユーザーエクスペリエンスを低下させる冗長インフラストラクチャに二重の作業を投資する理由は何ですか?

参照:

  1. トランスポート暗号化はすべての秘密を保護します

  2. ハッシュを送信することはパスワードを送信することと同じです 、そして 安全なハッシュの生成は必然的に遅くなります

  3. パスワードハッシュのbcryptとMD5のブルートフォース耐性? および ハッシュアルゴリズムのパフォーマンステスト結果

5
bishop