じぶん対策

日々学んだことをアウトプットして備忘録にしています。

OIDCを使用したクライアントシークレットなしでのソーシャルログイン実装について調査してみる

はじめに

最近OpenID Connect(OIDC)を使用したログインを実装するにあたって、implecit flowを用いる方法があることを教えてもらったので調査した結果をまとめてみます。

関連するRFCや信頼できそうな記事、理解しやすい記事を含めたいと思います。

参考: OIDCのImplicit FlowでClientSecretを使わずにID連携する

結論

  • OAuth2.0のimplicit flowはセキュリティリスクがある
  • OIDCのimplecit flowはOAuth2.0のimplicit flowと比較するとセキュリティリスクが少ない
  • ソーシャルログインを実現する場合、要件によってはOIDCのimplecit flowを使用することでクライアントシークレットの管理なしで実現できる
  • その場合はアクセストークンを発行してリソース取得エンドポイントを叩くのではなく、IDTokenに含まれる情報を使用する

OIDCとは

現代のウェブアプリケーションでは、ユーザーが他のサービスを通じて自身を認証する機能が実装されていることがあり、アカウント管理の煩雑さを解消し、開発者にとってはセキュリティのリスクや認証機能の実装の手間の削減を実現できます。このプロセスは「ソーシャルログイン」としてよく知られています。

OIDCはOAuth2.0という認可プロトコルを基盤とした認証の仕組みで、クライアントがエンドユーザーの同意を通じて、エンドユーザーの情報を安全に取得するための仕組みです。

OIDCのフロー

参考: OpenID Connect 全フロー解説

OIDCのフローは大きく以下のステップで構成されます。

  1. 認証認可リクエスト: クライアントはユーザーをOpenIDプロバイダー(例えばGoogle)の認可サーバーにリダイレクトします。この時、クライアントはリクエストにスコープopenidを含めます。

  2. ユーザー認証: ユーザーはOpenIDプロバイダーで自身のアイデンティティを認証します。成功すると、ユーザーはクライアントにリダイレクトされます。

  3. 認可レスポンス: リダイレクト時に、認可サーバーはcodeという認可コードをクライアントに渡します。

  4. トークンリクエスト: クライアントはこの認可コードを使い、認可サーバーにアクセストークンとIDトークンを要求します。

  5. トークンレスポンス: 認可サーバーはアクセストークンとIDトークンをクライアントに返します。

RFC6749に定義されているOAuth2.0の認可コードフローと同じフローになります。 このフローは、response_type=codeを指定した場合に実行されるフローとなります。 ただし、scopeopenidを含めた場合のみIDトークンが発行されます。

OIDCはIDトークンを発行するためのフローともいえると認識しているので基本的にはscopeopenidを含めることになると思います。

implecit flowについて

OAuth2.0にもimplecit flowが存在し、セキュリティ的なリスクがあって推奨されていないことは知っていたのですが、OIDCにもimplecit flowがあることを知らず、明確に違いを認識できていませんでした。 まずはOAuth2.0のimplecit flowについての復習から始めます。

OAuth2.0のimplecit flow

参考: OAuth 2.0 全フローの図解と動画

認可コードフローとは違い、認可エンドポイントにリクエストを投げ、応答として直接アクセストークンを受け取るフローです。

元々はJavaScriptを用いたブラウザベースのクライアント向けに設計されました。

フローの流れとしては以下のようになります。

  1. ユーザーがクライアントを認可すると、クライアントはリダイレクトURIにアクセストークンを含むリダイレクトレスポンスを受け取ります。
  2. クライアントはリダイレクトレスポンスからアクセストークンを抽出し、そのトークンを使用してリソースサーバーからリソースを取得します。

参考: OAuth 2.0 Implicit Grant Flow

ただ、このフローは設計上の脆弱性を持っています。 この脆弱性については以下の記事が詳しいです。

参考: OAuth 2.0 Implicit Flowをユーザー認証に利用する際のリスクと対策方法について #idcon

参考: 「単なるOAUTH 2.0を認証に使うと、車が通れるほどのどでかいセキュリティー・ホールができる」について

なお、RFCにおいても現在のセキュリティベストプラクティスをまとめた文書が発表されていて、原則認可コードフローの利用を推奨しています。また、PKCEを組み合わせて使用することが推奨されています。

OIDCのimplecit flow

OpenID Connectのimplecit flowはOAuth2.0のimplecit flowをベースにしています。そのため、同様のセキュリティリスクを抱えています。

ただし、OIDCのimplecit flowはOAuth2.0のimplecit flowとは異なり、IDトークンを発行するフローであり、このIDトークンにデジタル署名が含まれているため、クライアントはトークンが信頼できる発行者から発行され、改竄されていないことを確認できます。

ただし、OAuth 2.0のimplecit flowと同様に、IDトークンが直接ブラウザに渡されるため、トークンがブラウザの履歴やログ、HTTPリファラに記録される可能性は残っていますが、response_type=id_tokenを指定した場合はアクセストークンではなくID Tokenのみが記録されるため、OAuth 2.0のimplecit flowの問題に該当しないと思っています。

ただし、OIDCのセキュリティの利点を活用するためにはIDトークンの署名を検証することが大切です。

この署名の検討がOAuth2.0と大きく異なるセキュリティにおける重要なポイントです。

IDトークンについて

参考: IDトークンが分かれば OpenID Connect が分かる

参考: OpenID Connect Core 1.0 incorporating errata set 1

参考: JSON Web Token (JWT)

IDトークンはJWT形式で発行されます。このJWTには以下のようなクレーム(名前と値のペア)が含まれます。

クレーム 説明
iss トークンの発行者。これはトークンが誰から発行されたかを識別するためのもの。
sub 主題(Subject)。これはトークンが誰についてのものであるかを識別するためのもので、通常はユーザーの一意の識別子。
aud オーディエンス(Audience)。トークンの受け取り手を指定します。トークンはこのオーディエンスに対してのみ有効。
exp 有効期限(Expiration)。トークンの有効期限(UNIX時間)
iat 発行時刻(Issued At)。トークンが発行時刻(UNIX時間)
auth_time 認証時刻(Auth Time)。ユーザーが最後に認証された時刻(UNIX時間)
nonce リプレイ攻撃を防止するための文字列。リクエスト時にクライアントが送信し、IDトークンの発行時にそのまま返される。
acr 認証コンテクストクラス参照(Authentication Context Class Reference)。ユーザーの認証がどのレベルで行われたかを示すもの。
amr 認証方法参照(Authentication Methods References)。ユーザー認証に使用されたメソッド
azp 承認済みパーティ(Authorized party)。トークンが発行されたクライアント

これらはあくまでOIDCで定義された標準的なクレームなので、IDトークンはこれらに加えてカスタムクレームを持つこともできます。

ソーシャルログインの実装方針

今回の記事の目的であるクライアントシークレットの管理なしでログイン機能を実施するには、先述したIDトークンに含まれる情報を使用します。

IDトークンに含まれる情報は、ユーザーの識別子やメールアドレスなどの情報が含まれているため、これを使用してユーザーを識別することができます。

ログインのみの実装であれば発行者、ユーザーの識別子、クライアントの情報があれば実装できるため、クライアントシークレットの管理なしで実装できます。

まとめ

  • OAuth2.0のimplicit flowはセキュリティリスクがある
  • OIDCのimplecit flowはOAuth2.0のimplicit flowと比較するとアクセストークンではなくIDトークンが発行され、トークン自体の検証ができ、セキュリティリスクが少ない
  • ソーシャルログインを実現する場合、要件によってはOIDCのimplecit flowを使用することでクライアントシークレットの管理なしで実現できる
  • その場合はアクセストークンを発行してリソース取得エンドポイントを叩くのではなく、IDTokenに含まれる情報を使用する

所感

以前記事にしたりしてわかった気になっていた認証認可周りについて改めて調査しなおすいい機会になりました。 ただ闇雲に仕様を追うことだけでなく、要件を意識することの大切さを改めて感じた次第です。 こうした調査を通して、自分の知識の不足を感じることが多々ありますが、できる限り信頼のおける情報元を探し、こうしてアウトプットしていくことをこれからも継続していきたいと思います!