Site cover image

fhhm’s blog

👤OAuth2.0

OAuth2.0について勉強したので認可コードフローについてまとめてみる

概要

OAuth2.0は、ユーザーが認証情報を直接渡すことなく、第三者アプリケーションに限定的なアクセス権を与えるための認可(権限委譲)フレームワーク。アクセストークンを介して保護対象リソースへアクセスできる。認可コードフローなど複数のフローが存在する。

シーケンス

認可コードフロー(Authorization Code Grant)の基本的なシーケンス

💡アクターの説明

シーケンス図に登場するアクターについての説明と、Google Calendarに保存してある画像を読み込む場合の例

リソース所有者
  • リソースへのアクセス権を持つ人
    • e.g. Google Calendarに予定を登録しているユーザー
クライアント
  • リソース所有者に代わってリソースにアクセスしようとするアプリやサービス
    • e.g. Google Calendarに保存してある予定を参照できるアプリ(Notionなど)
認可サーバー
  • リソース所有者の同意を確認し、クライアントにアクセストークンを発行するサーバー
    • e.g. GoogleのOAuth認可サーバー
保護対象リソース
  • リソース所有者がアクセス権を持つリソース、または、そのリソースへアクセスできるAPIサーバー
  • e.g. Google Calendar API

sequenceDiagram
    participant RO as リソース所有者<br/>(Resource Owner)
    participant C as クライアント<br/>(Client)
    participant AS as 認可サーバー<br/>(Authrization Server)
    participant PR as 保護対象リソース<br/>(Protected Resource)

    C-->>RO: 認可エンドポイントへの<br/>リダイレクトを行わせる
    RO->>AS: 認可エンドポイントにアクセス<br/>(リダイレクト)
    AS->>RO: 認証を要求
    RO->>AS: 認証を実施<br/>クライアントを許可
    AS-->>RO: 認可コードを返却<br/>リダイレクトを行わせる
    RO->>C: リダイレクトで<br/>認可コードなどを送信
    C->>AS: 自身のクレデンシャルと認可コードを送信
    AS->>C: アクセストークンを返す
    C->>PR: アクセストークンを併せてリソース取得のリクエスト
    PR->>C: 保護対象リソースを返す

認可エンドポイント(/authorize)

クライアントから保護対象リソースへアクセスしようとすると、まずは認可サーバーの認可エンドポイント(/authorize)へリダイレクトされる。ここで、認証を行うことで、クライアントからリソースへのアクセスを許可することができる。このとき、許可するスコープを指定することができ、必要最低限の権限のみをクライアントに付与することが可能。認証に成功すると、認可コードが発行/返却される。

トークンエンドポイント(/token)

認可コードをトークンエンドポイントに送信することで、アクセストークンを取得することができる。以降では、このアクセストークンを使うことで、保護対象リソースにアクセスできるようになる。

セキュリティ対策

state

CSRF対策として機能する。下記を行うことで、意図しない認可リクエスト(攻撃者が誘導したもの)ではなく、自分自身がリクエストしたものだと判別することができる。

  • ランダムな文字列を認可リクエストに付与
  • 認可サーバーがその値をそのまま返却
  • リクエスト時に生成した値と返却された値が一致することを確認

codeVerifier/codeChallenge

中間者攻撃を防ぐために使われる。発行された認可コードがクライアントに届く前に横取りされた場合でも、攻撃者はcodeVerifierを知ることができないため、攻撃を防ぐことができる。

クライアント(認可リクエスト)
  • ランダムな文字列を生成し、codeVerifierとする
  • codeVerifierをハッシュ化し、Base64文字列に変換し、codeChallengeとする
  • (stateをキーに、)codeVerifierとcodeChallengeを保存
  • codeChallengeハッシュ化時に使用したアルゴリズム(codeChallengeMethod)を認可リクエストに付与する
認可サーバー(認可エンドポイント)
  • codeChallengeとcodeChallengeMethodがリクエストに含まれることを確認
  • 上記の値を認可コードと併せて保存
クライアント(トークンリクエスト)
  • 返却されたstateに紐づくcodeVerifier/codeChallengeを取得
  • codeVerifierをトークンリクエストに付与
認可サーバー(トークンエンドポイント)
  • 送られてきた認可コードに紐づくcodeChallenge/codeChallengeMethodを取得
  • 送られてきたcodeVerifierとcodeChallengeMethodを使用し、codeChallengeを計算
  • 認可リクエスト時に送られてきたCodeChallengeの値を一致するか確認

実装メモ

試しに書いてみたコード