2024.12.03
企業の情報漏えいで最も多いのは「中途退職者」による持ち出し 内部不正が発生しやすい3つの要素
リンクをコピー
記事をブックマーク
川崎貴彦氏:認可サーバーは基本的に2つのエンドポイントを提供します。その2つは、認可エンドポイントとトークンエンドポイントです。他にもさまざまな仕様があり、他のエンドポイントを定義している仕様もありますが今日は触れません。
このRFC 6749の仕様は、この2つのエンドポイントがどう動作すべきかを書いています。クライアントアプリケーションは、この2つのエンドポイントのどちらか一方もしくは両方のエンドポイントとやり取りをしてアクセストークンをゲットするのが目標です。
認可エンドポイントとトークンエンドポイントのどちらを使うのか、もしくは両方使うのかというのはフローの種類によって決まっています。認可コードフローの場合は両方のエンドポイントを使う。インプリシットフローの場合は認可エンドポイントしか使いません。リソースオーナー・パスワード・クレデンシャルズフローはトークンエンドポイントしか使わない。クライアントクレデンシャルズフローも同様です。
リフレッシュトークンもトークンエンドポイントしか使わない。なのでインプリシットフローしかサポートしていないのであれば、認可エンドポイントだけを実装すればいい。認可コードフローをサポートしたければ両方のエンドポイントを実装する必要があります。
この認可コードフローのイメージを見ていくと、登場人物としてはエンドユーザーとアプリケーションとサービスです。そして、認可サーバーを提供しているサービス、あとはそのサービスのリソースサーバーというものがあります。
まずアプリがユーザーに対して「サービスABCと連携しますか?」と聞いてくる。これに対してユーザーが「OK、連携していいよ」と言えば、このアプリからWebブラウザを経由して認可サーバーの認可エンドポイントに認可リクエストが投げられます。その認可リクエストを受けた認可エンドポイントは認可画面を生成してユーザのWebブラウザに返す。
その認可画面では「こんなアプリがこんな権限を求めています。承認しますか?」という画面がでます。そして、ユーザーは認可画面の内容を確認して、内容がよければ自分の認証情報を入れて「はい」ボタンを押す。そうすると、その情報が認可サーバーに伝わり、短命の認可コードが発行されます。
クライアントアプリがその認可コードを受け取ったら、それを同じ認可サーバーのトークンエンドポイントに提示して、その結果アクセストークンが発行される。ここまでが認可コードフローです。
アクセストークンが発行されたあとはアプリが、このアクセストークンを使って、リソースサーバのWeb APIにアクセスし、リソースを要求します。このあとはいくつか手順はありますが、リソースサーバーはそのアクセストークンが本当に正しいものかどうかを自分で直接調べてもいいし、認可サーバーに問い合わせてもかまいません。
ここでは認可サーバーに問い合わせる形式を図にしています。そのアクセストークンの情報を認可サーバーのイントロスぺクションエンドポイントというところに問い合わせる。その結果、イントロスぺクションエンドポイントはアクセストークンの情報を返してきます。そこでは、リソースサーバーはアクセストークンが有効かどうかを確認するんですね。
権限の有無や有効期限が切れていないかなどを調べたあとにOKが出れば、要求されたリソースをクライアントアプリケーションに返す。結果クライアントアプリはリソースを獲得する。
OAuth 2.0の仕様として、こういうフローがあります。この中でOAuth 2.0の仕様書で書かれている部分はどこかというと、この2、6、7、8のところです。とくにその認可画面とかは別に定義はありません。自由に作ってくださいといった感じです。
認可画面とかそこら辺の処理のところでユーザー認証が発生したり発生しなかったりしますが、そこはOAuthの仕様的にはどうでもよく、自由にやってくださいとなっています。それが、「OAuthはユーザー認証について定義していません」ということの理由です。次に、この2、6、7、8について少し細かく見ていきましょう。
2は認可リクエスト、6は認可レスポンス、7がトークンリクエスト、8がトークンレスポンスと呼ばれています。認可コードフローの認可リクエストは具体的にはこのHTTPのリクエストで、response_typeというパラメータがあったり、その下にclient_id、redirect_uri、scope、stateとあります。
このresponse_typeというのが重要なリクエストパラメータで、この値がcodeとなっていた場合は認可コードフローという意味です。そのリクエストを投げた結果、いろいろあったあとに認可レスポンスが返ってきますが、ここでcodeというパラメータで戻ってきます。これが発行された認可コードです。
この認可レスポンスはJSONで返ってくるのではなくてHTTPの302 Foundで返ってきます。Locationヘッダーにデータが入っている少し変わった形式です。これによってリダイレクトされてデータが渡ります。これは非常にわかりにくい部分ではあるんですけど、これについて何が起こっているかというと、まず認可サーバーが認可レスポンスを返す。その結果でリダイレクションが発生して、結果はコールバックにデータが飛んできて認可レスポンスパラメータをゲットできます。これを細かく説明するとすごい時間が掛かってしまうので紹介だけに留めて、詳細はブログに書いてあるのでそちらを見てください。
こんな感じでクライアントアプリケーションは認可レスポンスに含まれる認可レスポンスパラメータ群をゲットします。
次に、認可コードを受け取ったあとにクライアントアプリは何をするか。トークンリクエストについてです。ここで重要なのがgrant_typeというパラメータがありまして、この値がauthorization_codeだと認可コードフローでのトークンリクエストだとわかります。
ここのgrant_typeがauthorization_codeの場合は下のcodeは必須パラメータです。これは認可エンドポイントで発行された認可コードを表しています。こういうリクエストを投げて返ってくるトークンレスポンスはJSONで、その中にaccess_tokenというキーが入っている。その値が発行されたアクセストークンです。これが、認可コードフローです。
次にインプリシットフローの説明をします。OAuth 2.1の話やセキュリティベストカレントプラクティスなどいろいろあって、もうお聞きになっている方がいらっしゃると思いますが、インプリシットフローはもう使わないでくださいと言われているフローです。なので今後はこれを細かく勉強する必要はないんですけど、一応教養として知っておいたほうがいいということで説明をします。
これも最初にアプリが「サービスABCと連携しますか?」と聞いてくる。ここまでは認可コードフローと一緒です。認可コードフローではここで認可コードが発行されましたが、インプリシットフローではアクセストークンを直接発行するという流れになります。認可コード発行というワンクッションはありません。
ここまでがインプリシットフローです。アクセストークンをゲットしたあとはさっきと同じようにWeb APIコールをクライアントはできますという感じになります。このフローについて仕様書で定義されている部分は、ここの2と6の部分です。認可リクエストと認可レスポンスのフォーマットが仕様で決まっています。
これをよく見ていくと認可リクエストはHTTP GETのリクエストです。response_typeの値がtokenと書いてあった場合はインプリシットフローという意味になります。認可リクエストの結果、認可レスポンスが返ってきてそこでアクセストークンが発行されます。パラメータとしてここにaccess_tokenと書いてあるので、ここにアクセストークンが入っている状態です。
このレスポンスパラメータ群はフラグメント部に置かれ、フラグメント部というのは#で始まる部分以降のパラメータを指しています。これはクエリー部ではない、つまり「?」で始まっていない、という違いがあります。なぜこんな違いがあるのかというと、フラグメント部のパラメータ群というのはサーバーに送られないんですね。
それを参照できるのはWebブラウザやカスタムスキームハンドラだけ。なので、302でリダイレクトが起こってリダイレクトURIにWebブラウザをアクセスしに行くんだけど、アクセスしに行くときにここら辺のパラメータはサーバーに飛んでいきません。アクセストークンが飛んで行くのを避けようとしています。
何が起こるかというと、認可サーバーが認可レスポンスを返して……#になっていたりしますが、これでWebブラウザのLocationヘッダーが示す場所に遷移する。こんな感じでリクエストが飛んできます。これを受け取るのがコールバックのところ。
ただ、ここでは認可レスポンスのパラメータ群は見えない。#の後ろがフラグメント部なので、ここは飛んでこないので、認可レスポンスのパラメータ群を取得できません。このコールバックは、WebブラウザにJavaScriptを送り込みます。このJavaScriptはWebブラウザで動くアプリです。
そのアプリからだと、このURLのところにあるフラグメント部にアクセスできるので、そこからレスポンスパラメータをゲットできる仕組みになっています。インプリシットフローというのは基本的にWebブラウザの中で動くアプリが使うために用意されている感じです。ただ、最近はWebブラウザで動くアプリもインプリシットフローではなく認可コードフローをやりましょうという話になっています。
次にリソースオーナー・パスワード・クレデンシャルズフローの内容です。これも今は使ってはいけないと言われています。
もともとRFC 6749が決まって定義されたときも、このフローは定義するんだけども他に手段がない場合、もしくは移行手段、もともとユーザーIDとパスワードで全部APIコール、とかをOAuth形式に移行する場合の一時的なものとしてこれを使ってくださいという感じで用意されていました。
どういう内容かというと、アプリがユーザーに「サービスABCと連携しますか?」と聞きます。ユーザーが「はい」と答えると、アプリが「サービスABCにログインする際に使用するIDとパスワードを入力してください」という感じで要求してくるんですね。この画面を出しているのが認可サーバーではなくアプリというところがポイントです。
これで何が起こるかというと、そのアプリがユーザーに画面を表示して、ユーザーがIDとパスワードを入れようかなという感じになります。結果、トークンエンドポイントにトークンリクエストを投げる。その中にはユーザーが入力したIDとパスワードが含まれています。
ここで問題なのが、ユーザーが入力したIDとパスワードをこのアプリが取得できる点です。もし、このアプリが悪いアプリだった場合、このIDとパスワードを保存して悪用できてしまいます。以上がリソースオーナー・パスワード・クレデンシャルズフローの使用がおすすめできない理由です。
いずれにせよトークンリクエストを投げられたあとは、認可サーバーはアクセストークンをクライアントアプリに発行する。アクセストークンをもらったアプリはAPIコールが可能になります。仕様書で定義されているのはトークンリクエストとトークンレスポンスの中です。
これをHTTP的に見ていくと、アプリがトークンエンドポイントに直接アクセスしにいく。grant_typeの値がpasswordとなっていた場合、リソースオーナー・パスワード・クレデンシャルズフロー。なのでこのフローの場合は、usernameとpasswordを直接リクエストの中に埋め込んでしまっている状態です。なのでアプリは「そのIDとパスワードを教えてください」という感じでユーザーに聞いてきます。
この結果、戻ってくるJSONの中にaccess_tokenというのがあって、これが発行されたアクセストークンです。
次はクライアント・クレデンシャルズフロー。これはユーザーが絡まないフローです。要はクライアントに対してアクセストークンを発行する。クライアントアプリがユーザーに関係なくトークンエンドポイントにトークンリクエストを投げる。このリクエストの中にクライアントIDとクライアント・シークレットが含まれています。
他のクライアント認証方式を使うのであれば、普通はクライアントIDとクライアント・シークレットが含まれていて、トークンエンドポイントではそれを確認してアクセストークンを発行するという流れです。これでクライアントアプリはAPIコールができる。ただ、ここで発行されるアクセストークンはユーザーが絡んでいないので、ユーザーに紐づいたアクセストークンではありません。クライアントが誰ですよ、という情報しかないアクセストークンです。
ユーザーに関係ないAPI……例えば天気の情報を返すAPIだけだったらこれでもいい、と。ただ、もし天気のAPIがユーザーの住んでる地域に紐づいた天気を返すAPIだったらユーザーに紐づいたアクセストークンを返さないといけないですけど。
トークンリクエストとトークンレスポンスをHTTPレベルで見ていくとこんな感じですね。grant_typeのところにclient_credentialsと書いてあれば、これはクライアント・クレデンシャルズフローだとわかります。ここではクライアントは誰ですかという認証は確実に行わないといけないので、何らかの方法でクライアントのクレデンシャルズを含めます。
ここではAuthorizationヘッダーのところに含め、その結果アクセストークンが発行されるというところです。
あとはリフレッシュトークンフローというのもあります。アクセストークンの再発行を受けたので、認可処理をもう1回やらずに、そういうのをスキップしてトークンの再発行を受けることです。この場合は、まずリフレッシュトークンというものを予めクライアントアプリが持っていないといけない。過去の認可リクエストの結果、アクセストークンと一緒にリフレッシュトークンも発行されていることが前提です。
そのリフレッシュトークンを持っていれば、このクライアントアプリはトークンエンドポイントにリフレッシュトークンを持ってアクセスして、アクセストークンが発行される。アクセストークンが発行されればクライアントアプリケーションはWeb APIコールができます。
これもHTTPレベルで見ていくと、grant_typeがrefresh tokenとなっているので、これを見るとリフレッシュトークンフローなんだなということがわかります。リフレッシュトークンフローの場合は、refresh_tokenというパラメータは必須。発行されてあるリフレッシュトークンを指定すると、アクセストークンが再発行されます。
アクセストークンが再発行された結果、リフレッシュトークンも発行されることがありますが、これは発行しても発行しなくてもどちらでも可能です。また、アクセストークンの再発行リクエストにて指定されたものとは別のリフレッシュトークンを新しく発行してもいいし、リフレッシュトークンを一度使ったけどそのまま使い続ける選択もできます。どちらにするかは認可サーバーの実装次第です。Authleteの実装では、どちらでも選択可能になっています。
関連タグ:
2024.11.26
タスクの伝え方が部下のモチベーションを左右する マッキンゼー流、メンバーが動き出す仕事の振り方
2024.11.25
仕事はできるのに、なぜか尊敬されない人が使いがちな言葉5選 老害化を防ぐために大切な心構えとは
2024.11.27
何もせず月収1,000万円超…オンラインゲームにハマって起こした事業 大学中退し4社立ち上げ・2社売却した起業家人生
2024.11.29
「明日までにお願いできますか?」ちょっとカチンとくる一言 頭がいい人に見える上品な言い方に変えるコツ
2024.11.25
論理的に「詰める」マネジメントでは本質的な解決にならない マッキンゼー流、メンバーの理解と納得を得る接し方
2024.11.28
管理職の「疲弊感」がメンバーに伝わるリスク 部下の「働きがい」を育む6つのポイント
2024.11.27
部下に残業させられず、自分の負担ばかり増える管理職 組織成長のカギを握る「ミドル層」が抱える課題
2024.11.27
仕事中の「今ちょっといいですか」が苦痛… いしかわゆき氏が語る、ADHD気質にマッチした働き方のヒント
2024.11.26
仕事の質を左右する「ムダな習慣」トップ5 忙しくなる前に棚卸ししたい“やめたほうがいいこと”とは
2024.11.28
“新規事業が生まれない組織”に足りていないもの 「PoC貧乏」に陥らず、アイデアを形にするためのヒント
長期投資の衝撃の真実!20年投資しても年率1.9%しか増えない!?
2024.10.04 - 2024.10.04
第765回 トレンド経営学『顧客に謝る基準とは?』
2022.04.18 - 2022.04.18
不機嫌な自分をやめるために!認知行動療法の専門家 中島美鈴先生新刊『脱イライラ習慣! あなたの怒り取扱説明書』発売記念【無料オンラインイベント】
2024.10.25 - 2024.10.25
ログミーBusiness リニューアル記念イベント開催
2024.11.29 - 2024.11.29
品がある人、育ちがいい人の見える 人のセリフ 3選
2022.11.30 - 2022.11.30