私はRESTアプリケーションをSpring Frameworkを使用して開発しています。要件の一部として、システムのさまざまな機能をさまざまなユーザーロール(かなり標準的なもの)に保護する必要があります)。現在ログインしているユーザーのロールを決定する方法は、フロントエンドからREST urlを呼び出すたびに、リクエストヘッダーにBase 64エンコードされた文字列を追加することです。この文字列はデコードされるとユーザー名に解決され、bCryptが生成したパスワードハッシュは、username:hashedpasswordの形式になります。
リクエストが安全なHTTP接続を介して行われる場合でも、これが安全ではないことを少し心配しています。少なくともユーザーのユーザー名にハッカーがアクセスする可能性があるためです。パスワードを取得できませんでした。これはハッシュ値なので、そのハッシュ値を使用してREST APIを正常に呼び出すことができます。
このシステムを適切に保護するにはどうすればよいですか?セッションにセッショントークンまたはランダムに生成された何らかのキーを追加する必要がありますか?
私のフォローアップの質問は、それをどのようにしてRESTfulに実行できるかということです。ログイン時にusername:hashedpasswordを表すハッシュを(bCryptを使用して)生成し、それをデータベースに保存して、REST呼び出しが行われるたびにそれをチェックすることができると考えていました。ユーザーはログアウトし、それをnullに設定するだけです。すすぎと繰り返し。これにより、潜在的な攻撃者はユーザー名を公開しない単一のbCrypt文字列のみを取得しますが、その文字列を使用してREST API。
次のリンクは、詳細な回答を提供する場合があります。
行うすべてのリクエストでユーザー名とパスワードの組み合わせを使用しない方がよいことに注意してください。ユーザーを認証し、サーバー側でトークンを生成し、それをクライアントに(Cookieなどで)通信し、そのトークンを後続の要求の認証として使用する方が適切です。このリンクは、そのプロセスをガイドします: https://github.com/OWASP/CheatSheetSeries/blob/master/cheatsheets/Session_Management_Cheat_Sheet.md 。
認証を提供する必要があるだけで、ネットワーク経由で送信されるデータが機密ではない場合は、SSLのオーバーヘッド/レイテンシなしのより良い方法があります。
モバイルクライアントアプリがあるとします。最初にユーザーにサインアップまたは登録してもらい、メール(ユーザー名)とパスワードを別のWebフォーム(アプリまたはRESTサービスの一部ではありません)で入力します。次に、登録が成功すると、ユーザーキー(対称暗号化の場合はサーバー(データベース)のユーザーアカウントに格納されている共有秘密キー、または対応する秘密キーがサーバー(データベース)のユーザーアカウントに格納されている非対称暗号化の場合は公開キー) SSL経由のWebフォームを使用してすべて行われます。
ここで、ユーザーがクライアントアプリを開いたときに、RESTfulサービスへのすべてのリクエストで送信される資格情報をユーザーに要求する必要があります。彼らは、以前に受け取った名前、パスワード、および暗号化キーを提供する必要があります。これは一度だけ行う必要があります。次に、アプリは各リクエストに次のようなHTTPヘッダーを提供します。
AUTHENTICATE> username:timestamp:encrypted {password:timestamp}/AUTHENTICATE>
{}内のパスワードとタイムスタンプの両方がユーザーのキーを使用して暗号化されることに注意してください。タイムスタンプは、すべてのリクエストで更新されます。
次の処理を行うサーバーに認証フィルターを実装します。
最初にタイムスタンプを確認し、有効期限が切れている(たとえば1秒より古い)場合は、UNAUTHORIZED HTTP応答コードを送信します。タイムスタンプが有効な場合は、ユーザーアカウントデータベースでユーザー名を検索します。見つからない場合は、UNAUTHORIZED HTTP応答を送信します。ユーザー名が見つかった場合は、そのユーザーの保存されている暗号化キーをフェッチします(これは、共有秘密キーまたはユーザーの公開キーの秘密キーである可能性があることに注意してください)。暗号化された{password:timestamp}を復号化します。暗号化解除されたパスワードは、データベースに格納されているユーザーパスワードと一致する必要があり(パスワード自体は、セキュリティを強化するために別のキーを使用してデータベースで暗号化することもできます)、復号化されたタイムスタンプも、上記のAUTHENTICATEヘッダーで送信された暗号化されていないタイムスタンプと一致する必要があります。そうでない場合は、UNAUTHORIZED HTTP応答コードを送信します。成功した場合、リクエストはCookie /セッションを使用せずに認証されています。
ユーザーの詳細をキャッシュして、リクエストごとにデータベースの検索を行わないようにすることもできます。
誰かがスヌーピングしてリクエストをインターセプトすると、タイムスタンプが無効になるか、暗号化されていないタイムスタンプを有効に更新した場合、それを再利用してアクセスすることができなくなります。認証フィルターがそれを復号化します)。
単一のアプリキーを使用するこのアプローチのもう1つの利点は、データベースのユーザーアカウントに有効期限を設定することで、サービスにアクセスできるユーザーを完全に制御できることです(サブスクリプションベースのサービスを効果的に実装)。これは素晴らしいことです。最初に、トライアルサブスクリプション(たとえば1年間無料)でできるだけ多くのユーザーを獲得し、アカウントの有効期限を延長するために支払いをしていなければ、後でそのユーザーへのアクセスをブロックする必要があるためです。