1. 序章

新しいHTTPAPIを作成するときはいつでも、URLパターン、リソース構造など、いくつかの決定を行う必要があります。 重要な決定の1つは、クライアントがAPIにアクセスするためにどのように認証できるかです。

このチュートリアルでは、いくつかの選択肢とその長所と短所を見ていきます。

2. 従来の認証

HTTP仕様は、リクエストを認証するためのいくつかの簡単な手段を提供します。 これらは、基本認証およびダイジェスト認証として知られています。

基本認証は、ユーザー名とパスワードを「:」区切り文字で組み合わせ、結果の文字列をbase64でエンコードすることで機能します。これは、「基本」スキームを使用してAuthorizationヘッダーで提供されます。 たとえば、ユーザー名「baeldung」とパスワード「superSecret:」の場合

  • 2つを「baeldung:superSecret」に結合します
  • Base64は、この文字列を「YmFlbGR1bmc6c3VwZXJTZWNyZXQ=」にエンコードします
  • これを「認証:基本YmFlbGR1bmc6c3VwZXJTZWNyZXQ=」のHTTPヘッダーで指定します

HTTPサーバーは、これを元のユーザー名とパスワードに簡単に変換して、正しいことを確認できます。 ただし、これにはセキュリティ上の影響があります。 パスワードはリクエストごとに提供されるため、簡単に傍受される可能性があります。

ダイジェスト認証は、ユーザー名、パスワード、およびその他の詳細の暗号ダイジェストを生成することにより、これを改善します。この情報は、ユーザー名およびその他の詳細とともにサーバーに送信されます。 サーバーはパスワードを検索し、同じダイジェストを生成して、それらを比較できます。

これは、パスワードがどのような形式でもネットワーク経由で送信されず、代わりにサーバーが同じダイジェストを生成する必要があるため、有利です。つまり、同じ詳細にアクセスする必要があります。 したがって、パスワードはサーバーでプレーンテキストで利用できる必要があります。

これらのメカニズムは両方とも、ユーザーがすべての要求で認証されることも必要とします。 これには、ユーザーの詳細を検索し、すべての要求でパスワードを検証することが含まれます。 これは、特にユーザーの詳細を取得するためにリモートサービスを参照する必要がある場合は、コストがかかる可能性があります。

3. トークンベースの認証

1つの方法は、クライアントを1回認証し、その際に、認証済みであることを証明する特別なトークンをクライアントに提供することです。これは「アクセストークン」と呼ばれ、サーバーが使用できるものです。認証の完全なプロセスを実行する必要なしに、ユーザーが誰であるかを証明します。

トークンベースの認証には、認証されたユーザーのトークンを生成できる特別なインフラストラクチャと、トークンが有効であることを確認する手段が必要です。 ただし、これにより、ユーザー認証を残りのサービスから切り離すことができ、将来のAPI呼び出しではこのトークンのみが提供され、ユーザーの実際の資格情報は提供されません。 これは、OAuth2OpenIDConnectなどの仕様で提供されているものです。 これらは、将来のAPI呼び出しで使用するトークンを取得するためのさまざまな手段を説明しています。

トークンがとる正確な形式は、私たちの正確なニーズによって異なります。 単純な値を使用して、データベースでそれらを検索し、それらが何を表しているかを確認できます。 JWT などの自己完結型の形式を使用することもできます。これは、それらが有効であることを確認するだけでよいことを意味します。

セキュリティ上の理由から、トークンを漏らしたり共有したりしてはなりません。ただし、違反を簡単に封じ込めるために、トークンを短命にする機能があります。 OAuth2などの仕様には、新しいトークンを定期的に要求する方法があり、アクセストークンを定期的にローテーションできます。

また、攻撃者がトークンを推測したり生成したりできないようにすることも重要です。 JWTなどの形式を使用すると、生成されたすべてのトークンが一意であることが保証され、認証サーバーによって生成されたことが証明されます。  他のサービスは、非同期暗号化署名を使用するか、共有署名キーを使用して、トークンが正しく生成されたことを確認できます。

これは、同じトークンを使用して複数のサービスに対して認証できるため、有益です。各サービスがトークンを検証できる限り、それらは正しく機能します。 これは、同じAPIゲートウェイが前面にない分散サービスを構築する場合に役立ちます。

トークンに単純なIDを使用する場合は、非決定的な方法で生成されることが重要です。 増分番号が使用されている場合、攻撃者は他の番号を試して何が起こるかを確認できます。 UUIDなどを使用すると、攻撃者が有効なトークンを予測できる可能性がはるかに低くなります。

4. セッションベースの認証

もう1つの方法は、多くのコンテナから利用できるセッションインフラストラクチャを利用することです。 Tomcat。 セッションは、セッションIDに対して単純なデータを格納する手段として機能し、webappコンテナーはこれらのストレージを管理し、セッションIDに関連付けます。

これを使用して、ログインしたユーザーをセッションに保存することで認証を実装できます。 ユーザーがセッションに存在する場合、これは認証されたユーザーです。 ユーザーがいない場合、現在認証されていません。 必要に応じて、ユーザーの権限のセットやその他の潜在的に役立つデータなど、追加のデータをセッションに保存できます。

通常、これらのIDは、Cookieによって、またはURLに挿入することによって送信されます。 コンテナが私たちのために多くの仕事をするので、これははるかに便利です。 ただし、これは、アプリケーションがこれらの範囲内で動作する場合にのみ当てはまります。 たとえば、URLへのセッションIDの挿入は、URL自体を生成しているAPIクライアントと組み合わせて使用するとうまく機能しません。

コンテナは、セッションのライフサイクル全体も処理します。これには、不要になったときに期限切れになることも含まれます。 多くの場合、これは特定の時点ではなく、非アクティブな期間に関連付けられています。 つまり、ユーザーはシステムをアクティブに使用している間だけ認証されたままになり、ユーザーが終了すると、セッションは期限切れになり、認証されなくなります。

ただし、複雑な問題があります。 セッションの使用はストレージへのアクセスに依存し、同じクライアントからのすべての呼び出しが単一のサーバーに到達するか、サーバー間のセッションレプリケーションを構成する必要があります。 さらに、ログアウトを処理するための何らかの方法が必要です。 これを実現する一般的な方法は、セッション全体を期限切れにするか、ユーザーの詳細をクリアすることです。

5. 概要

APIを認証する方法を決定することは、簡単な選択ではありません。 バランスを取る必要があるものがいくつかあります。セキュリティへの影響、実装コスト、展開コストなどです。

一般に、トークンベースの認証は、特にOAuth2やOpenIDConnectなどのフレームワークを使用する場合に一般的です。 つまり、サードパーティのクライアントは、これらの概念をすでに理解しているツールを使用できるため、私たちとのやり取りが簡単になります。

ただし、セッションベースの認証は通常、アプリケーションコンテナの標準機能であるため、単一のサービス内に実装する方が簡単な場合があります。 これは、APIの開発コストは低くなりますが、クライアントにとってはコストが高くなることを意味します。