概要
OAuth 2.0とOpenID Connectは、Webサービス間の認証と認可を実現するためのプロトコルです。OAuth 2.0は主に認可に重点を置いていますが、アクセストークンの奪取やリダイレクト先の偽装などのセキュリティリスクが存在します。一方、OpenID Connectは認証に特化し、IDトークンを用いることでよりセキュアな認証を提供します。この2つのプロトコルを組み合わせることで、認可と認証の両方を安全に実現し、シングルサインオンも可能になります。本記事では、OAuth 2.0のリスクと対策、OpenID Connectのセキュリティ機能、両者の連携方法、IDトークンとアクセストークンの役割について詳しく解説します。
OAuth 2.0のリスクと対策
OAuth 2.0は便利な認可フレームワークですが、いくつかのセキュリティリスクが存在します。主なリスクとしては、アクセストークンの奪取、リダイレクト先の偽装、中継サーバーの悪用などがあります。これらのリスクに対しては、TLSの使用、アクセストークンの有効期限を短く設定する、リダイレクトのステータスコードを適切に設定する、HTML文書の埋め込み機能を制限するなどの対策が有効です。OAuth 2.0を安全に使うためには、仕様を正しく理解し、想定される脅威に応じた適切な実装を行うことが重要です。
OpenID Connectのセキュリティ機能
OpenID Connectには、OAuth 2.0のセキュリティリスクに対処するための機能が組み込まれています。例えば、IDトークンには発行者(iss)、対象者(sub)、利用者(aud)などの情報が含まれており、想定外のアプリケーションからのログインを検出できます。また、OpenID Connectでは二段階認証・多要素認証などの追加のセキュリティ機能を利用することも可能です。OpenID Connectを適切に実装・運用することで、OAuth 2.0の脆弱性を補いつつ、より安全なシングルサインオンを実現できます。
OAuth 2.0の代表的な脆弱性
OAuth 2.0には、以下のような代表的な脆弱性が存在します。
- アクセストークンの推測や盗聴による奪取
アクセストークンが推測可能な値である場合や、通信経路上で盗聴された場合、不正にアクセストークンが奪取されるリスクがあります。 - クライアントからのアクセストークン奪取
クライアント(アプリケーション)のセキュリティ対策が不十分な場合、クライアントに保存されたアクセストークンが奪取される可能性があります。 - 認可エンドポイントのオープンリダイレクター脆弱性
認可サーバーのリダイレクトURIのバリデーションが不十分な場合、認可コードやアクセストークンが意図しない宛先に渡される可能性があります。 - 中継サーバーの自動接続機能の悪用
中継サーバーの設定が不適切な場合、アクセストークンを自動的に中継サーバーに引き渡してしまう可能性があります。 - リソースオーナーのクレデンシャル情報の漏洩
認証時のセッション管理が不適切な場合、リソースオーナーのクレデンシャル情報(パスワード等)が漏洩するリスクがあります。
これらの脆弱性に対しては、アクセストークンを推測困難な値にする、TLSで通信を暗号化する、クライアントのセキュリティ対策を十分に行う、リダイレクトURIを厳密にチェックする、中継サーバーの設定を適切に行う、セッション管理を適切に行うなどの対策が必要です。
OAuth 2.0とOpenID Connectの連携
OAuth 2.0とOpenID Connectは、それぞれ認可と認証に特化したプロトコルですが、実際のアプリケーションでは両者を組み合わせて使用することが一般的です。その理由は以下の通りです。
- 認可と認証の両方が必要とされるケースが多い
多くのアプリケーションでは、ユーザーを認証した上で、そのユーザーに応じた権限でAPIリソースへのアクセスを認可する必要があります。OAuth 2.0は認可に、OpenID Connectは認証に特化しているため、両者を組み合わせることでこのようなケースに対応できます。 - OpenID ConnectがOAuth 2.0をベースにしている
OpenID ConnectはOAuth 2.0の認可フローをベースに、ID連携の仕組みを追加したプロトコルです。そのため、OAuth 2.0の実装があれば、OpenID Connectを比較的容易に導入できます。逆に、OpenID Connectを使う場合、下位レイヤーとしてOAuth 2.0の実装が必要になります。 - セキュリティリスクへの対策
OAuth 2.0には、アクセストークンの奪取や、クライアントへのなりすましなどのセキュリティリスクがあります。OpenID Connectでは、署名付きのIDトークンを使うことで、トークンの改ざんを防止し、クライアントの正当性を確認できます。OAuth 2.0とOpenID Connectを組み合わせることで、これらのリスクを軽減できます。 - シングルサインオンの実現
OpenID Connectを使えば、複数のアプリケーション間でのシングルサインオン(SSO)を実現できます。ユーザーは一度の認証で複数のアプリケーションを利用できるようになります。一方、OAuth 2.0単体ではSSOを実現するのは難しいです。OpenID ConnectとOAuth 2.0を組み合わせることで、SSOと認可を両立できます。
このように、OAuth 2.0とOpenID Connectは相互に補完しあう関係にあります。実際のアプリケーションでは、認可はOAuth 2.0、認証はOpenID Connectを使い、両者を組み合わせて使うことが一般的です。これにより、セキュアな認可と認証を実現しつつ、シングルサインオンも可能になります。
OpenID Connect認証
OpenID Connectは、OAuth 2.0をベースに認証機能を拡張したプロトコルです。OpenID Connectでは、認証情報をIDトークンと呼ばれるJSONデータとして提供します。IDトークンには、発行者(iss)、対象者(sub)、利用者(aud)、発行日時(iat)、有効期限(exp)などの情報が含まれており、トークンの正当性を検証できます。OpenID Connectの認証フローは以下のようになります。
- クライアント(Relying Party)がOpenID Provider(OP)の認可エンドポイントにリクエストを送信
- OPがエンドユーザーを認証し、同意を得る
- OPがクライアントにIDトークンと認可コードを返す
- クライアントが認可コードをOPのトークンエンドポイントに送信
- OPがクライアントにアクセストークンを返す
このフローにより、クライアントはエンドユーザーの認証情報(IDトークン)と、APIアクセスのための認可情報(アクセストークン)を安全に取得できます。OpenID Connectでは、IDトークンの署名検証により、トークンの改ざんを検出できます。また、クレームベースのアクセス制御により、より細かい粒度でのAPIアクセス制御が可能です。OpenID Connectを使うことで、OAuth 2.0の認可機能に加えて、セキュアなシングルサインオンを実現できるのです。
IDトークンとは
IDトークンとは、OpenID Connect (OIDC)で定義されているJSON Web Token (JWT)の一種で、認証されたエンドユーザーのアイデンティティ情報を含むトークンのことです。IDトークンは、OIDCの認証フローにおいて、OpenID Provider (OP)からクライアント(Relying Party)に発行されます。IDトークンには以下のような情報が含まれています。
- iss (Issuer) : IDトークンの発行者 (OpenID Provider)
- sub (Subject) : エンドユーザーの識別子
- aud (Audience) : IDトークンの利用者 (クライアント)
- exp (Expiration time) : IDトークンの有効期限
- iat (Issued at) : IDトークンの発行時刻
- nonce (Nonce) : リプレイ攻撃防止のためのランダムな値
- auth_time (Authentication time) : エンドユーザーの認証時刻
また、IDトークンにはエンドユーザーのプロフィール情報(名前、メールアドレスなど)が含まれることもあります。IDトークンはJWTとしてエンコードされ、OPの秘密鍵で署名が付与されます。クライアントはOPから取得した公開鍵を使ってIDトークンの署名を検証することで、トークンの完全性と真正性を確認します。クライアントはIDトークンをデコードすることで、認証されたエンドユーザーの情報を取得できます。ただし、IDトークンはあくまでエンドユーザーの認証情報を示すものであり、APIアクセスの認可に使うべきではありません。APIアクセスにはアクセストークンを使う必要があります。このようにIDトークンは、OpenID Connectにおける認証情報の受け渡しに重要な役割を果たしています。OPとクライアントの間で安全にエンドユーザーのアイデンティティ情報を共有することを可能にしているのです。
IDトークンの署名検証
OpenID ConnectではIDトークンの署名検証により、トークンの改ざんを検出し、発行者の正当性を確認しています。具体的には以下のようなプロセスで署名検証が行われます。
- OpenID Provider(OP)は秘密鍵を使ってIDトークンに署名を付与する。署名アルゴリズムはRS256 (RSA Signature with SHA-256)が一般的。
- OPは公開鍵をJWKS (JSON Web Key Set)エンドポイントで公開する。JWKSには署名検証に必要な公開鍵の情報が含まれる。
- クライアント(Relying Party)はOPのJWKSエンドポイントから公開鍵を取得する。
- クライアントは取得した公開鍵を使ってIDトークンの署名を検証する。署名が正しければ、トークンが改ざんされていないことと、正当なOPによって発行されたことが保証される。
- 署名検証に加えて、クライアントはissクレーム(発行者)、expクレーム(有効期限)、audクレーム(想定されるクライアント)などのクレームの値を検証し、トークンの有効性を確認する。
このようにOpenID Connectでは、非対称鍵暗号方式による署名と検証により、IDトークンの完全性と真正性を担保しています。これによりクライアントは、受け取ったIDトークンが信頼できるOpenID Providerによって発行され、内容が改ざんされていないことを確認できるのです。
アクセストークンとは
アクセストークンとは、OAuth 2.0で定義されているトークンの一種で、保護されたリソース(APIなど)にアクセスするための認可情報を含むトークンのことです。アクセストークンは、OAuth 2.0の認可フローにおいて、認可サーバー(Authorization Server)からクライアント(アプリケーション)に発行されます。アクセストークンには以下のような情報が含まれることがあります。
- トークンの発行者 (issuer)
- トークンの利用者 (client_id)
- トークンの有効期限 (expiration time)
- トークンの対象となるリソース (scope)
- トークンの対象となるユーザー (username)
アクセストークンの形式は実装によって異なりますが、JWTが使われることも多いです。JWTの場合、アクセストークンにはヘッダー、ペイロード、署名が含まれます。ペイロードには上記のようなクレームが含まれます。クライアントは、APIリクエストのAuthorizationヘッダーにアクセストークンを指定することで、保護されたリソースにアクセスできます。リソースサーバー(APIサーバー)は、アクセストークンを検証し、トークンに含まれるスコープ(scope)の範囲内でリソースへのアクセスを許可します。アクセストークンの有効期限は通常短く設定され、リフレッシュトークンと組み合わせて使われることが多いです。これにより、アクセストークンが漏洩した場合の影響を最小限に抑えつつ、一定期間はアクセスを継続できるようになっています。このようにアクセストークンは、OAuth 2.0における認可情報の受け渡しに重要な役割を果たしています。クライアントとリソースサーバーの間で安全にアクセス権限を共有することを可能にしているのです。ただし、アクセストークンはあくまで認可のためのトークンであり、認証に使うべきではありません。認証にはIDトークンを使う必要があります。
リソースサーバーによるアクセストークン検証
リソースサーバーは、クライアントから受け取ったアクセストークンを検証することで、APIリソースへのアクセスを認可します。具体的には以下のような手順でアクセストークンの検証が行われます。
- クライアントは、APIリクエストのAuthorizationヘッダーにアクセストークンを指定してリソースサーバーにリクエストを送信する。
- リソースサーバーは、Authorizationヘッダーからアクセストークンを取り出す。
- リソースサーバーは、アクセストークンの署名を検証する。アクセストークンがJWTの場合、認可サーバーの公開鍵を使って署名を検証する。これにより、トークンが改ざんされていないこと、および正当な認可サーバーによって発行されたことを確認する。
- リソースサーバーは、アクセストークンの有効期限 (exp) を確認する。有効期限が切れている場合は、アクセスを拒否する。
- リソースサーバーは、アクセストークンに含まれるスコープ (scope) を確認する。リクエストされたAPIリソースへのアクセスが、スコープで許可された範囲内であることを確認する。
- リソースサーバーは、アクセストークンに含まれるクライアントID (client_id) を確認する。トークンが、APIリソースへのアクセスを許可されたクライアントに発行されたものであることを確認する。
- 必要に応じて、リソースサーバーは認可サーバーのイントロスペクションエンドポイントを呼び出し、アクセストークンの有効性を確認する。これにより、認可サーバー側でトークンが失効されていないことを確認できる。
以上の手順により、リソースサーバーはアクセストークンの有効性と正当性を確認し、APIリソースへのアクセス可否を判断します。アクセストークンの検証に失敗した場合、リソースサーバーはクライアントにエラーレスポンスを返します。リソースサーバーとしては、アクセストークンの検証を適切に行うことが重要です。不正なアクセストークンを受け入れてしまうと、APIリソースが不正にアクセスされる可能性があります。一方、有効なアクセストークンを誤って拒否してしまうと、正当なクライアントがAPIを利用できなくなってしまいます。このように、リソースサーバーはアクセストークンの検証を通じて、OAuth 2.0における認可制御の最後の砦となっているのです。
アクセストークンの有効期限の確認方法
リソースサーバーは、アクセストークンの有効期限(exp)クレームを確認することで、トークンの有効期限を検証します。expクレームは、トークンの有効期限を示すUNIX時間(1970年1月1日からの経過秒数)で表されます。リソースサーバーは、現在時刻とexpクレームの値を比較し、現在時刻がexpよりも後の場合はトークンが期限切れであると判断します。一般的には、リソースサーバーはNTPなどを用いて時刻を同期し、正確な現在時刻を取得します。また、有効期限の判定には多少のマージンを設けることが推奨されています。これは、クライアントとサーバー間の時刻のずれや、通信遅延などを考慮するためです。例えば、expの5分前までをトークンの有効期間とみなすなどの実装が考えられます。
アクセストークンの検証に使用されるアルゴリズム
アクセストークンの検証に使用されるアルゴリズムは、トークンの形式によって異なります。一般的には、アクセストークンとしてJWT(JSON Web Token)が使用される場合、RS256(RSA Signature with SHA-256)やES256(ECDSA Signature with SHA-256)などの非対称鍵暗号アルゴリズムが使われます。これらのアルゴリズムでは、認可サーバーが秘密鍵で署名を生成し、リソースサーバーが公開鍵で署名を検証します。一方、アクセストークンがランダムな文字列(Opaque Token)の場合、リソースサーバーは認可サーバーのイントロスペクションエンドポイントを呼び出してトークンの有効性を確認します。この場合、リソースサーバーと認可サーバー間の通信は、TLSなどを用いて暗号化・認証される必要があります。
アクセストークンの無効化方法
アクセストークンの無効化は、主に認可サーバー側で行われます。一般的な方法としては、以下のようなものがあります。
- アクセストークンの有効期限を短く設定する
アクセストークンの有効期限を短く設定することで、トークンが漏洩した場合の影響を限定的にできます。ただし、有効期限が短すぎるとクライアントは頻繁にトークンを更新する必要があるため、適切なバランスを取る必要があります。 - リフレッシュトークンを用いてアクセストークンを無効化する
リフレッシュトークンを用いてアクセストークンを更新する際に、古いアクセストークンを無効化することができます。これにより、アクセストークンが漏洩した場合でも、一定時間後には自動的に無効化されます。 - 認可サーバー側でアクセストークンを失効させる
認可サーバーは、アクセストークンを明示的に失効させることができます。これは、ユーザーがアプリケーションとの連携を解除した場合や、アクセストークンが漏洩したことが判明した場合などに行われます。失効したトークンは、イントロスペクションエンドポイントで無効であると判定されます。
以上のような方法により、アクセストークンを適切に無効化することで、不正アクセスのリスクを軽減できます。
まとめ
この記事では、OAuth 2.0とOpenID ConnectにおけるアクセストークンとIDトークンの役割と違いについて解説しました。
アクセストークンはOAuth 2.0で定義された、APIリソースへのアクセスを認可するためのトークンです。リソースサーバーによって検証され、APIアクセスの可否を判断するために使われます。
一方、IDトークンはOpenID Connectで定義された、認証されたエンドユーザーの情報を含むトークンです。クライアントによって検証され、エンドユーザーの認証情報を確認するために使われます。
アクセストークンとIDトークンは、役割と用途が異なるため、混同して使うべきではありません。OAuth 2.0とOpenID Connectを適切に組み合わせて使うことで、APIリソースの認可とエンドユーザーの認証を安全に実現できます。