OAuth2.0やOpenID Connectなど体系だった情報や初心者でも分かりやすい記事が分散していたので、これらを整理した。
この後は、実際に手を動かしながら理解を深めていこうと思う。
ここでは全体像をはっきりとさせることが趣旨なので、詳細は該当リンクを参照してください。
認証と認可の違い
- 認証
- 通信の相手が誰であるかを確認すること
- 英語では、Authentication
- 認可
- ある特定の条件に対して、リソースアクセスの権限を与えること
- 英語では、Authorization
OAuthとは
「第三者のアプリケーションにユーザーの ID & パスワードを渡さない」ことを目的にした認可の仕組み(引用元)
OAuth 2.0 とは、サービスのユーザーが、サービス上にホストされている自分のデータへのアクセスを、自分のクレデンシャルズ (ID & パスワード) を渡すことなく、第三者のアプリケーションに許可するためのフレームワークである。
例えば、facebookのプロフィール情報をあるSNS(第三者のアプリケーション)に取り込みたい場合、そのSNSに自分のfacebookのクレデンシャル(IDとパスワード)を保存させて取得させるのではなく、プロフィール情報へのアクセスをさせることができる。
OAuth2.0(OpenID Connect)のアクター
- Client(Relying Party, RP)
- 認可を受け、保護されたリソースに対して何かしらのアクションを行う
- Authorization Server(OpenID Provider, OP, Identity Provider, IdP)
- リソース所有者の同意を得て、保護されたリソースに対してアクセストークン(IDトークン)を発行する
- Resource Server
- OAuthによって保護されたリソースを所有するサーバで、Authorization Serverと同じであることがほとんど
- Resource Owner
- OAuthによって保護されたリソースを持つユーザ(大抵は、人間)
認可フロー
- Resource Owner requests Client
- ユーザが認可を要求するアプリケーション
- Redirect to Authorization Server & Authorization Request
- Authorization Serverのアプリケーションへリダイレクトされ、認可を要求する
- End-User Authentication & Consent
- ユーザがそのアプリケーションで認証され、認可することを合意する
- Redirect back to Client & Authorization Response to Client
- Clientへリダイレクトされ、Authorization Serverからのレスポンスを受け取る
- API Request
- ClientからResource Serverへアクセストークンを使ってリソースへのアクションを実行する
- 認可コードフロー
- Authorization ResponseでClientに認可コードが渡される
- その後、認可コードと予め取得したclient_id, client_secretを使ってToken Requestをする
- インプリシットフロー
- Authorization ResponseでClientにアクセストークンが渡される
- リソース所有者パスワードクレデンシャルフロー
- Authorization RequestでResource OwnerのクレデンシャルをClientから渡す
- Clientにクレデンシャルは丸見えだが、保存する必要はなくなる
- それで認証できれば、Authorization ResponseでClientにアクセストークンが渡される
- Authorization RequestでResource OwnerのクレデンシャルをClientから渡す
- クライアントクレデンシャルフロー
- ユーザとは無関係のリソースへのアクセスへの認可の際に利用される
- Authorization RequestでClientのクレデンシャルをClientから渡す
- それで認証できれば、Authorization ResponseでClientにアクセストークンが渡される
- Authorization Request時のstateとトークン取得時のResponseのstateが一致するかチェックする
- CSRF対策
- API Requestでは、アクセストークンはAuthorizationヘッダに格納する
- ヘッダはWebサーバのログに残ることがほとんどない
- ヘッダがWebサーバやブラウザのキャッシュに残ることもほとんどない
- アクセストークンとその有効期限を一緒に保存し、利用時に確かめる
- リクエストを送る前にリフレッシュトークンを使うべきか判断できる
トークン置換攻撃
- 内容
-
API Request時に別のResource Ownerのアクセストークンを使わせることで、別のユーザのリソースを操作すること
- Clientがアクセストークンを受け取って、Resource ServerにAPI Requestをする
- その時に、別のResource OwnerのアクセストークンをClientに渡すことで実現できる
- 別のResource Ownerのアクセストークンはそれ用のClientアプリケーションを作ることで取得できる
- インプリシットフローやClientのフロント側からバックエンド側にトークンを渡す時などに起きやすい
-
API Request時に別のResource Ownerのアクセストークンを使わせることで、別のユーザのリソースを操作すること
- 原因
- OAuthは認可をデリゲーションするためのプロトコルであり、ユーザ認証はできないから
- 対策
- OpenID Connectを使って、「どのClientにどのユーザのリソースを認可したのか」を確認できるようにする
- それを検証することで該当ユーザに紐づいたリソースであることを認証することができる
OpenID Connectの概要
- 目的(引用元)
- どのクライアントでどのユーザが認証されたかを明らかにすることで、アクセストークンとユーザの情報の対応が正しいことを検証できるようにする
それは、ユーザーが認証されたという事実とそのユーザーの属性情報を、捏造されていないことを確認可能な方法で、各所に引き回すためです。 一ヶ所で(=一つの OpenID プロバイダーで)ユーザー認証をおこない、発行された ID トークンを引き回すことができれば、別の場所で何度もユーザー認証を繰り返す必要がなくなります。 短く言うと、『ID 連携』ができます。
- フロー(引用元)
- OAuth2.0の認可フローでアクセストークンを渡す時にはIDトークンも渡す
双方の処理フローが似ているのは、OpenID Connect が OAuth 2.0 の拡張仕様だからです。 OAuth 2.0 はアクセストークンを発行するための処理フローを定めていますが、それを流用し、ID トークンも発行できるようにしたのが OpenID Connect なのです。 これについて、OpenID Connect のウェブサイトでは、「アイデンティティー・認証と OAuth 2.0 を足したものが OpenID Connect である」と説明したりしています。
ID Token(JSON Web Signature(JWS)形式)
- 構成要素のヘッダー、ペイロード、署名をbase64urlでエンコードしてピリオドで繋げたID Token
-
主な構成要素
- ヘッダー
- alg: 署名に用いる暗号アルゴリズム(公開鍵暗号方式を使うことでclientサイドで共通鍵を管理する必要がなくなる)
- ペイロード(JSON Web Token(JWT)(ジョットと読む))
- iss: トークンの発行者(issuer)
- sub: ユーザ識別子(subject)
- aud: クライアント識別子(audience)
- nonce: Authorization Response to Clientの時と同じ文字列(number used once)(CSRF対策)
- 署名
- 改竄されていなければ、base64urlでデコードし復号すると「ヘッダー.ペイロード」になる
- ヘッダー
- 他のID Tokenの形式
- JSON Web Encryption(JWE)
- ヘッダー、キー、初期ベクター、暗号文、認証タグをbase64urlでエンコードしてピリオドで繋げたID Token
- JWTが暗号文になっている
- JSON Web Encryption(JWE)