web-dev-qa-db-ja.com

API認証にHMAC-SHA1を使用する-クライアントパスワードを安全に保存する方法は?

S3-style 認証を使用するRESTful APIでは、APIクライアントはHMAC-SHA1を使用して秘密鍵で要求に署名するため、秘密鍵がネットワーク経由で送信されることはありません。次に、サーバーは、クライアントの秘密鍵を使用してクライアントを認証し、署名プロセス自体を繰り返し、その結果をクライアントによって送信された署名と比較します。

これはすべて素晴らしいことですが、サーバーがクライアントの共有シークレットのプレーンテキストにアクセスする必要があることを意味します。これは、データベース内の平文にユーザーパスワードを保存することに対するあらゆるアドバイスに直面しています。パスワードのソルトハッシュのみを保存することは、私が知る限りオプションではありません。その場合、クライアントの署名を確認できないためです。

私のAPIはRESTfulであり、したがってステートレスである必要があることを強調する必要があります。他のAPI呼び出しの前にログイン手順を回避したいのです。

オプションの解決策の1つは、対称鍵アルゴリズムを使用してすべてのユーザーパスワードを暗号化することです。ただし、サーバーはその暗号化のキーをどこかに簡単にアクセスできる保存する必要があります。ソースコード内。これは何もないよりはましですが、最適な解決策ではありません(@Rookが彼の回答で述べたように、CWE-257に違反しています)。

解決策のもう1つの方向性は、非対称署名に関するものである可能性がありますが、それをHMACに適用する方法がわかりません。また、このテーマに関する記事も見つかりません。

ここで明らかな何かが欠けていますか?多くの立派なプロバイダーがこの種の認証スキームを実装しています-それらすべてが一般的なセキュリティ原則に違反しているわけではありませんか?そうでない場合、共有できるベストプラクティスはありますか?

31
Elad

これは、対称鍵チャレンジ/レスポンススタイルの認証の欠点です。シークレットをネットワークに配置しませんが、両端にシークレットを保存する必要があります。 (HMACは対称鍵システムです)。

パスワードではないことに注意してください-共有秘密です。ここには根本的な違いがあります。パスワードは通常ユーザーが選択しますが、共有シークレットはランダムに生成されてユーザーに提供されます(このコンテキストでは「APIキー」と呼ばれることがよくあります)。

データベースが危険にさらされた場合、攻撃者は他の場所で使用された可能性のある(そしておそらく使用された)パスワードを取得したため、パスワードを可逆形式で保存することは良くありません。一方、共有シークレットを保存することはそれほど問題ではありません。サービスに固有のシークレットであるため、攻撃者が取得したのは、サービスにログインする機能だけです。

一方、サーバー側にシークレットを格納する必要のない非対称システムを持つことは可能です。基本的な考え方は、サーバーがクライアントの公開鍵と現在のメッセージシーケンス番号を知っているということです。 APIリクエストを送信するとき、クライアントはメッセージシーケンス番号をインクリメントし、シーケンス番号とAPIリクエストパラメータの署名を計算します。これらはサーバーが公開鍵を使用して確認できます。メッセージに古いメッセージシーケンス番号が含まれている場合、サーバーはリプレイ攻撃を防ぐためにメッセージを拒否します。

34
caf

理想的には、ユーザーがログインした後、そのセッションの存続期間中、HMAC秘密鍵Kとして使用されるCryptographicNonceをユーザーに提供します。これは安全なアプローチですが、RESTはステートレスであるため、RESTfulではありません。ログインごとに発行されるメッセージ認証コードのこの考え方は、技術的には状態の形式です。

パスワードを暗号化してデータベースに保存することは、 CWE-257 の違反です。

11
rook

ここで何かが足りないかどうかはわかりませんが、1つのオプションは、ハッシュされたパスワードを対称鍵として使用することです。

2
Pushpendra