現在、Androidクライアントによって使用されるRESTのようなAPIでユーザー認証を実装しています。いくつかの調査の結果、JWT(JSON Web Token)がそのための良い方法だと思います。
私が計画した基本的な手順は次のとおりです。ユーザーはユーザー名/パスワードを使用してログインします(HTTPS経由)。サーバーはパスワードを検証してから、ある種のユーザーIDを含むJWTを生成し、RS256(RSAを使用して非対称なので、クライアントは対応する公開鍵しか持たない)で署名し、それをクライアントに送信します。 API呼び出しを行うために、クライアントはJWTをサーバーに送信します。次に、サーバーが行うことはすべて、その秘密鍵を使用してJWTを検証し、署名アルゴリズムがサーバーによって予期されたものであることを確認することです。検証が成功した場合、サーバーはトークン内のユーザーIDを信頼できます。 JWTのペイロードが変更された場合、正しい署名を生成するにはサーバーの秘密鍵が必要になるため、クライアントは別のユーザーのふりをすることはできません。
次に、代わりにHS256(HMACを使用して対称)を使用したいとします。これは、結果の署名が短いためと考えられます。私の常識としては、この場合、サーバーだけが(単一の)キーを知ることができます。
しかし、ここで混乱が生じます。JWTでHS256を使用することを読んで、私が見たいくつかのサイトは、キーが「共有シークレット」、つまりサーバーとクライアントの両方がそれを知っていることを示唆しているようです。ただし、その場合、クライアントはJWTのペイロードを変更し、共有キーを使用して有効な署名を作成するだけで済みます。ログインしたユーザーは、JWTでユーザーIDを変更するだけで他のユーザーになりすますことができるため、署名をまったく検証しないのと同じです。 HS256を使用しているときにクライアントにキーへのアクセスを許可しても意味がありませんか? HS256キーが共有されていることを示唆するサイトを誤解していませんか?
私がそれについて考えることができる唯一の方法は、両方の当事者がキーを知ることができるようにすることで、ユーザーごとに別々のキーを使用することです。しかし、それでも、ユーザーID(「isAdmin」フラグなど)以外のJWTペイロードデータは自由に変更できます。
この場合の「共有シークレット」は、通常、クライアントとサーバー間ではなく、複数のサーバー間を意味します。通常、JWTは対称暗号化を使用して実行できます。この場合、トークンを検証する必要があるすべてのサーバーは共有シークレットを保持する必要があります-または非対称暗号化を使用します。他のサーバーは、公開鍵を使用して、トークンが適切に署名されていることを確認できます。
いかなる場合でも、クライアントはトークンを変更することができません。クライアントは、資格情報を提示するとトークンを受け取り、トークンを使用して、同じサーバーから、または承認サーバーと信頼関係を共有する他のサーバーからサービスを取得します(公開/秘密鍵の知識または共有鍵を介して)