web-dev-qa-db-ja.com

ユーザーデータをユーザーパスワードでクライアント側で暗号化

私のアプリケーションがユーザーデータのクライアント側を暗号化し、そのデータをサーバーに送信できるようにするスキームを絞り込みました。サーバーがデータを復号化する可能性はありません。

このスキームに明らかな欠陥がないことを確認したいと思います。

メソッド

注:以下のすべての手順はクライアント側で行われます。

前駆:

  1. ログイン/登録時に、グローバルキーgk = SHA256(user_password)を生成し、gkを格納します クッキー ローカルストレージ。 (これの理由は、ユーザーのパスワードをわかりやすく保存しないためです。)

暗号化:

  1. すべてのファイルについて、ランダムキーfkを生成します。
  2. fkでファイルを暗号化します。
  3. gkfkを暗号化して、fk '
  4. 暗号化されたファイルとfk 'をサーバーに送信して保存します。

復号化:

  1. 暗号化されたファイルとfk 'をサーバーから受信します。
  2. gkを使用してfk 'を復号化し、fk
  3. fkを使用してファイルを復号化します。

ユーザーがパスワードを変更した場合:

  1. すべてのファイルについて、現在のgkを使用してfk 'を復号化し、fk
  2. 新しいパスワードを使用して新しいgkを生成します。
  3. fkを新しいgkで暗号化してfk '
  4. 新しいファイルfk 'をサーバーに送信して保存します。

ユーザーがパスワードを忘れた場合:

  1. 運が悪い。 (そうでなければ?)

この手順にはどのような欠陥がありますか?

更新

1つの欠点は、ユーザーがパスワードでログインを認証した場合、技術的にはgkを簡単に計算してサーバーに保存できるため、クライアント側の暗号化。

これに対する解決策:

  1. pw = SHA256(SHA256(user_password))を生成し、これをユーザーのパスワードとしてサーバーに送信します。サーバーはこのパスワードを受信し、保存する前に再度暗号化します。

つまり、サーバーに関する限り、サーバーは通常のパスワードを受け取っているだけです。しかし、この方法では、gkをサーバー側で計算することはできません。

欠陥?

4
Snowman

このスキームの最大の欠点は、(a)サーバーによってクライアントに送信されるJavaScriptコードに依存することです。

では、すべてのセキュリティ対策を回避するクライアントの変更されたJavaScriptを送信するために、サーバー(またはその中間)を維持するために何をすべきでしょうか。クライアント、さらに言えば、ユーザーはこれまでにどのように知っていますか?指紋、チェックサム、デジタル署名などをチェックするために作成するすべてのコードも同様に回避できます。

関連する問題は、ブラウザで実行されている、セキュリティ関連のJavaScriptコードから確実に分離できない他の悪意のあるJavaScriptコードです。

これを修正することは不可能です。ブラウザー内のJavascriptは現在安全なプラットフォームではなく、すべてのブラウザーのクライアント側の暗号化は、閉じることができないこのギャップのあるセキュリティホールに悩まされています。

更新された質問に関するコメントでの議論の要約

Pw = sha256(sha256(user_password))を計算することは、いくつかの理由で私を悪い考えと思います。

  1. 最初の1つはすでにAgentMeで言及されています。パスワードをハッシュするために、sha-whateverなどの単純なハッシュ関数を使用しないでください。これらのハッシュ関数は、ハードウェアに効率的に実装されるように設計されており、非常に高速です。パスワードをハッシュするには、遅いハッシュ関数が必要です。 AgentMeの回答を参照してください。
  2. このスキームでは、gk(sha256(user_password)のみ)を知っていれば、pwを計算できます。したがって、誰かがローカルストレージを盗むとき、マスター暗号化キーと、暗号化されたファイルをダウンロードするために必要な認証/承認トークンの両方へのアクセスを許可します。 2つのシークレットを互いに独立させておくほうがよいので、一方がサードパーティによって侵害された場合、もう一方のシークレットを計算して暗号化データの機密性を破るだけでは不十分です。
  3. 最後に、このスキームでuser_passwordをソルトしていません。つまり、ユーザーベース全体で同じパスワードを使用しても同じハッシュ値が生成されます(数百万の最も一般的なパスワードを含む無塩のシャハッシュ用の大きなRainbowテーブルがすでに存在しています)。

あなたは、例えば、代替案を提案しますgk = sha256(user_password)およびpw = sha128(user_password)。これはポイント2を解決しますが、1と3には対応していません。また、攻撃者に追加の情報(2つの異なるハッシュ値にハッシュされた同じパスワード)を不必要に提供すると想像できるので、私はそれをお勧めしません。それを悪用する方法がわかりません。

Gk = hmac(user_password、n)とpw = hmac(user_password、m)を使用することをお勧めします。mとnは既知ですが、ユーザーごとに異なります。 mとnに到達する方法は、それらがランダムで十分に大きく、ユーザーベース全体でそれらを高い確率で一意にする限り、関係ありません。それらをクライアントで作成し、サーバーに保存するために送信し、ユーザー名でインデックスを付けて、他のクライアントで取得できるようにすることができます。または、ユーザーが最初にアカウントを作成するときにサーバーにそれらを生成させることができます。値を安全に保つ必要はありません。 user_passwordがなければ、価値がありません。改善点は、gk = hmac(bcrypt(user_password)、n)およびpw = hmac(bcrypt(user_password)、m)を使用してブルートフォース攻撃を困難にすることです。

さて、hmacは認証トークンや暗号化キーを作成するためではなくメッセージ認証用に設計されているので、この提案が良い考えであるとは確信していません。しかし、これは私が提起した3つのポイントすべてを解決するようです。そのため、同じハッシュ関数をチェーンするか、パスワードに2つの異なるハッシュ関数を使用するよりも、優れたソリューションのようです。

5
Out of Band
  1. Cookieはサーバーに送信されるため、gkはCookieではなくlocalStorage/IndexedDBに保存する必要があります。
  2. ブルートフォースに耐性のあるSHA256よりも強力なパスワードハッシュ/キー導出アルゴリズムを使用する必要があります。
  3. ユーザーはサーバーに対してどのように認証しますか?暗号化されたfk'他のユーザーのファイル。プレーンテキストのパスワードを送信する以外の方法でユーザーを認証する必要があります。キー導出関数を介して入力されたgk値を2回送信することもできます。
  4. https://www.nccgroup.trust/us/about-us/newsroom-and-events/blog/2011/august/javascript-cryptography-considered-harmful/ を参照してください。あなた(またはあなたを強制している人、またはあなたをハッキングした人)は、サーバーが提供するJavaScriptを変更してユーザーのgk値をサーバーに送信するか、そうでなければそれらをリークすることで、ユーザーデータを取得できます。これは、オープンにレビューされたコードを持つService Workerを上手に使用することで軽減できますが、だれかがまだ十分にそれを行っているかどうかはわかりません。
1
Macil