OAuthとは何か?

Jinhua Luo

November 18, 2022

Technology

さまざまなウェブサイトで新しいアカウントを作成することは、常に面倒な作業でした。ほとんどの場合、名前や電話番号などの同じユーザー情報を繰り返し入力する必要があるため、冗長な作業です。

「パスワードを渡さずにアプリに自分のデータにアクセスさせることができるのか?」

OAuthは、この問題を解決するために集中型の認可を提供する標準です。

OAuthは「Open Authorization」の略で、アクセス委任のためのオープンな標準です。これにより、リソース所有者であるあなたは、パスワードを公開することなく、アプリケーションやウェブサイト間で情報を共有できます。OAuthは広く使用されており、あなたも日常的にOAuthサービスを利用しているかもしれません。例えば、GeeksforGeekにログインする際に、Googleアカウントを使用してログインすることを選択できます。これにより、GeeksforGeekにGoogleアカウントのユーザー名やプロフィール写真などの情報にアクセスする権限を付与します。

OAuth Signing in Example

OAuthの歴史

OAuth 1.0プロトコルは、2010年4月に情報提供のためのRFC(Request for Comments)としてRFC 5849として公開されました。

OAuth 2.0プロトコルは、2012年10月にRFC 6749として公開され、OAuth 2.0 Bearer Token UsageはRFC 6750として公開されました。

OAuth 1.0の展開経験を基に構築されていますが、OAuth 2.0はOAuth 1.0を一から完全に書き直したものであり、全体的な目標と一般的なユーザー体験のみを共有しています。OAuth 2.0はOAuth 1.0と後方互換性がありません。

OAuth 2.0の仕組み

OAuthプロトコルでは、リソース所有者のユーザー名とパスワードを使用して保護されたリソースにアクセスする代わりに、クライアントアクセストークンを使用します。クライアントは、リソース所有者の承認を得て、認可サーバーからアクセストークンを取得します。リソース所有者がクライアントに認可を付与するためには、まずアプリケーションで認証される必要があります。そして、認証はリソース所有者とアプリケーションの間でのみ行われるため、第三者のクライアントはリソース所有者のプライベートな情報を知ることができません。

OAuthプロトコルを実装することで、第三者のクライアントの認証プロセスが大幅に簡素化されることがわかります。クライアントが行う必要があるのは、ユーザーから認可を得て、アクセストークンを要求し、それを使用してユーザー情報(保護されたリソース)を取得することです。新しいユーザーにアカウント登録を要求したり、資格情報を公開したりする必要がないため、攻撃対象を減らし、ネットワークセキュリティを向上させます。

OAuthは認証ではありません。ここでのAuthは認可を意味します。ユーザーはアプリケーションにログインするのではなく、第三者のアプリケーションに自分の情報の一部を取得する権限を付与するだけです。

OAuthの認可プロセス

役割

OAuthは4つの役割を定義しています:

クライアント - リソース所有者のデータにアクセスし、リソース所有者の代わりに保護されたリソースリクエストを行うアプリケーション。

リソース所有者 - リソースサーバーにデータを所有し、クライアントのサービスを利用したいユーザーで、認可サーバーにアカウントを持っています。例えば、私は自分のFacebookプロフィールのリソース所有者であり、GeeksforGeeksのサービスを利用したいと考えています。

認可サーバー - OAuthの主要なエンジン。リソース所有者の認証に成功し、認可を得た後、クライアントにアクセストークンを発行します。

リソースサーバー - クライアントが求めるデータを保存するサーバーで、アクセストークンを使用して保護されたリソースリクエストを受け入れ、応答することができます。

OAuthプロトコルのフロー

oauth protocol flow

ステップA: 第三者のアプリケーションがユーザーに認可を要求します。

ステップB: 第三者のアプリケーションが認可グラントを受け取ります。これはリソース所有者の認可を表す資格情報です。

ステップC: 第三者のアプリケーションが認可グラントを使用してアクセストークンを要求します。

ステップD: 認可サーバーがクライアントを認証し、認可グラントを検証します。有効であれば、第三者のアプリケーションにアクセストークンを発行します。

ステップE: 第三者のアプリケーションがアクセストークンを使用してリソースサーバーから保護されたリソースを要求します。

ステップF: リソースサーバーがアクセストークンを検証し、有効であればリクエストに応答します。

認可コードとアクセストークン

認可サーバーからアクセストークンを取得するための認可グラントには4つのタイプがあります。ここでは、最も安全で一般的な方法である認可コード方式についてのみ説明します。

oauth flow - authorization code mode

ステップA: 第三者のアプリケーションがユーザーに認可方法(例:GitHub)を選択させ、client_idredirect_uriなどのパラメータを付けて認可サーバーにリダイレクトします。

リクエスト例:

    GET /authorize?response_type=code&client_id=s6BhdRkqt3&state=xyz
        &redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb HTTP/1.1
    Host: server.example.com

ステップB: ユーザーがログインして認可します。

ステップC: 認可サーバーがredirect_uriに従ってユーザーを第三者のアプリケーションのバックエンドにリダイレクトし、認可コードを提供します。

レスポンス例:

     HTTP/1.1 302 Found
     Location: https://client.example.com/cb?code=SplxlOBeZQQYbYS6WxSbIA
               &state=xyz

ステップD: 第三者のアプリケーションが認可コードを使用して認可サーバーからアクセストークンを交換します。

リクエスト例:

     POST /token HTTP/1.1
     Host: server.example.com
     Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
     Content-Type: application/x-www-form-urlencoded

     grant_type=authorization_code&code=SplxlOBeZQQYbYS6WxSbIA
     &redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb

ステップE: 認可サーバーが検証し、アクセストークンを返します。

認可サーバーからのレスポンス例:

     HTTP/1.1 200 OK
     Content-Type: application/json;charset=UTF-8
     Cache-Control: no-store
     Pragma: no-cache

     {
       "access_token":"2YotnFZFEjr1zCsicMWpAA",
       "token_type":"example",
       "expires_in":3600,
       "refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA",
       "example_parameter":"example_value"
     }

具体的な例

Bobは、Rabbitというソフトウェアを使用してAmazonの注文をきれいに印刷したいと考えています。

リソース所有者 -> Bob

クライアント(第三者のアプリケーション) -> Rabbitソフトウェア

認可サーバー -> Amazonの認可サーバー

リソースサーバー -> Amazonの注文情報を保存するデータベース

保護されたリソース -> Amazon上のBobの注文情報

OAuth Flow Example - Amazon order

なぜ認可コードとアクセストークンを別々に取得する必要があるのか?

認可コードとアクセストークンを別々に取得するのは、セキュリティ対策を確保するためです。

OAuth2プロトコルでは、認可コードはクライアントがアクセストークンと交換するための一時的なコードです。このコードは認可サーバーから取得され、ユーザー(リソース所有者)はクライアントが要求する情報を確認し、リクエストを承認または拒否する機会があります。

ユーザーがログインして認可に成功すると、一時的な認可コードがURLに含まれてアプリケーションにリダイレクトされます。

この認可コードは通常10分間有効で、1回のみ使用できます。短い有効期間により、ユーザー情報が漏洩するリスクが低減されます。一方、access_tokenの有効期間は比較的長く、通常1〜2時間です。これが漏洩すると、ユーザーのデータセキュリティに大きな危険が及ぶ可能性があります。

さらに、アクセストークンを交換するために、クライアントは認可コードに加えてclient IDclient secretを提供する必要があります。認可サーバーはこれらのパラメータを使用してクライアントを認証し、アクセストークンを要求する者が信頼できるかどうかを確認します。認可コードが不幸にも漏洩した場合でも、ハッカーがclient IDclient secretを持っていなければ、アクセスコードを取得することはできません。仮にclient IDclient secretを持っていたとしても、認可コードは1回のみ有効であるため、クライアントサーバーと競争する必要があります。このメカニズムにより、潜在的な攻撃の難易度が大幅に向上します。認可コードを取得するステップをスキップしてアクセストークンを直接返すと、攻撃者がアクセストークンを使用してユーザー情報を簡単に盗む可能性があります。

OIDC(OpenID Connect)

OAuthを使用して認可を行う目的は何でしょうか?それは、ユーザーに関するさまざまな情報を取得することです。なぜ、第三者のアプリケーションが直接使用できるように出力を標準化できないのでしょうか?

OIDCはこの標準化を行います。

OIDCはどのようにしてこれを行うのでしょうか?簡単に言えば、access tokenとともにJWT形式のid_tokenを返し、基本的なユーザー情報を含めます。第三者のアプリケーションは、署名アルゴリズムを確認し、id_tokenの署名を公開鍵で検証することでユーザー情報を取得できます。

さらに、OIDCはUserInfoエンドポイントを提供します。第三者のサービスは、アクセストークンを使用してこのエンドポイントにアクセスし、ユーザーの追加情報を取得できます。

OIDCのもう一つの特徴は、シングルサインオン(SSO)とシングルログアウト(SLO)です。SSOは、ユーザーが異なるクライアントとの認証済みセッションを持ち、毎回資格情報を提供する必要がないようにすることで、使いやすさを向上させます。ユーザーが1つのアプリケーションにログインに成功すると、他のアプリケーションにログインする際に再度パスワードを入力する必要がありません。

SLOは、ユーザーがシングルログアウトを開始した後、SSOセッションからアクティブなセッションが残らないようにすることでセキュリティを向上させます。ユーザーは一度ログアウトするだけで、すべてのセッションが終了し、ハイジャックや悪用を防ぎます。

OIDCは、パスワードや顔認証などの特定の認証方法を標準化しているわけではないことに注意してください。代わりに、認証を集中型の認証プロバイダーに委任する方法、認証後に得られるもの - id token、このトークンがどのように検証されるか - JWT形式、およびこのid tokenに含まれるユーザー情報を指定しています。これにより、第三者のアプリケーションは車輪の再発明をする必要がなくなります。

APISIXのOAuth/OIDCサポート

Apache APISIXは、オープンソースのクラウドネイティブAPIゲートウェイです。これは動的でリアルタイムの高性能APIゲートウェイであり、従来の南北トラフィックだけでなく、サービス間の東西トラフィックも処理できます。また、k8s ingressコントローラーとしても使用できます。

APISIXは、複数のアップストリームアプリケーションサーバーのプロキシとして機能するAPIゲートウェイであるため、集中型の認可と認証をAPIゲートウェイに配置するのが最も自然です。

APISIXのOpenID Connect(OIDC)プラグインは、OpenID Connectプロトコルをサポートしています。ユーザーはこのプラグインを使用して、APISIXをOkta、Keycloak、Ory Hydra、Authingなどの多くのアイデンティティプロバイダー(IdP)と接続し、集中型認証ゲートウェイとして展開できます。OIDCはOAuthのスーパーセットであるため、このプラグインはOAuthもサポートします。

展開図:

Deployment diagram of apisix and oauth

設定例:Apache APISIXとKeycloakを統合して認証を行う

Keycloakの設定

パラメータ
keycloakアドレスhttp://127.0.0.1:8080/
レルムmyrealm
クライアントタイプOpenID Connect
クライアントIDmyclient
クライアントシークレットe91CKZQwhxyDqpkP0YFUJBxiXJ0ikJhq
リダイレクトURIhttp://127.0.0.1:9080/anything/callback
ディスカバリーhttp://127.0.0.1:8080/realms/myrealm/.well-known/openid-configuration
ログアウトURI/anything/logout
ユーザー名myuser
パスワードmyrealm
レルムmypassword

サンプルコード

curl -XPUT 127.0.0.1:9080/apisix/admin/routes/1 -H "X-API-KEY: edd1c9f034335f136f87ad84b625c8f1" -d '{
    "uri":"/anything/*",
    "plugins": {
        "openid-connect": {
            "client_id": "myclient",
            "client_secret": "e91CKZQwhxyDqpkP0YFUJBxiXJ0ikJhq",
            "discovery": "http://127.0.0.1:8080/realms/myrealm/.well-known/openid-configuration",
            "scope": "openid profile",
            "bearer_only": false,
            "realm": "myrealm",
            "redirect_uri": "http://127.0.0.1:9080/anything/callback",
            "logout_path": "/anything/logout"
        }
    },
    "upstream":{
        "type":"roundrobin",
        "nodes":{
            "httpbin.org:80":1
        }
    }
}'

APIが正常に作成された後、http://127.0.0.1:9080/anything/testにアクセスすると、ログインしていないためKeycloakのログインページにリダイレクトされます:

apisix keycloak login

ユーザー名としてmyuser、パスワードとしてmypasswordを入力すると、次のページにリダイレクトされます。

apisix keycloak authorized

http://127.0.0.1:9080/anything/logoutにアクセスしてログアウトします:

apisix keycloak logout

まとめ

要約すると、OAuth標準はアプリケーションとユーザーの両方にとって人気のあるソリューションです。ユーザーが資格情報を共有することなく、複数のプラットフォームでサービスを利用できるようにすることで、利便性とセキュリティを提供します。Apache APISIXは、さまざまなアイデンティティプロバイダー(Keycloak、Ory Hydra、Okta、Auth0など)との統合をサポートする人気のAPIゲートウェイであり、APIを保護します。

さらに詳しく読む:

Share article link