OAuth 2.0 の Client Type についての考え方
ritou です。
OAuth 2.0 のクライアントの種類、いわゆる Client Type についての基本的なお話です。
よくある認識
仕様だと
- Public : ClientSecret を安全に管理できず、他の方法でもセキュアなクライアント認証ができないクライアント
- Confidential : ClientSecret を安全に管理できる、または他の方法でセキュアなクライアント認証ができるクライアント
と書いてあり、実際の分類となると
- Webアプリ : Confidential
- モバイルアプリ、SPA、デスクトップアプリ : Public
となります。
Webサーバーの内部など、ある程度アクセス制限のされた状態で管理されているが、SPAのソースコードやモバイルアプリのバイナリの解析とかによって取得しうるみたいなのは直感的かと思いますが、これだけだといろいろ迷う人がいるらしい、ということでもう少しこのClient Typeの違いを整理しておきましょう。
第3者が知りうる通信内容
ClientSecret の管理だけではなく、どのリクエスト/レスポンスの内容を第3者、と言っても主に "User-Agentやモバイル端末自体の機能にアクセスできる存在" が知りうるかどうかも理解しておく必要があるでしょう。
"Confidential"
Webアプリが認可コードフローを使う場合のシーケンスを示します。
Confidential Client では User-Agent に関わる、認可リクエスト/レスポンスのところでUser-Agentの利用者などが関与できます。
素の OAuth 2.0 の認証リクエスト/レスポンスは単純なGETリクエストであるので、ブラウザのURL欄を書き換えることも可能です。このような操作で問題が起こり得るような場合は、別の拡張機能などを用いて認可リクエスト/レスポンスを安全に保護する必要があります。
"Public"
次に、モバイルアプリが単体で認可コードフローを使う場合のシーケンスを示します。
Public Client の場合は User-Agent に関わる、認可リクエスト/レスポンスのところだけではなく、クライアントであるモバイルアプリと認可サーバー/クライアント-リソースサーバーとのやりとりの部分でもプロキシサービスなどを用いて通信内容を知りうる可能性があります。
よって、例えばClientSecretを難読化して埋め込んだり、プラットフォームが提供するセキュアな保存領域に保存できたとして、無理やり解析以外にも上記の通信にそのまま含まれる値であれば、その値は秘匿できない、と考える方が良いでしょう。
第3者がアクセスできる情報、できない情報
ここまでを整理します。OAuth 2.0のClient Typeとクレデンシャルの中で第3者がアクセスできる情報としては、以下のようになります。
Public | Confidential | |
---|---|---|
ClientID | ◯ (認可リクエスト、アクセストークンリクエスト、ソースコード) | ◯ (認可リクエスト) |
ClientSecret | ◯ (アクセストークンリクエスト、ソースコード) | × |
AccessToken | ◯ (アクセストークンレスポンス) | × |
RefreshToken | ◯ (アクセストークンレスポンス、アクセストークンリフレッシュリクエスト) | × |
これらの特徴を考慮して、例えば認可サーバー側で Public Client 向けの Access Token について
- 有効期限は短く
- 付与される scope を制限
- Refresh Tokenを発行しない
などの実装がされることがあります。
"Public" Client + Backend Server
"Public" な Client であるサービスはだいたいBackend Serverとやりとりします。
BackendServerとの役割分担によって、全体で見たときの Client Type が変わってきます。
"取得したトークンを渡す" なら "Public" のまま
まずは "Public" な Client が取得したトークンを Backend Server に送信してリソースアクセスパターンです。
当然ながらこのパターンではトークン取得までのフローが変わらないのでリスクも変わらず、全体としても "Public" な Client と言えるでしょう。
前にOAuth認証についての記事を書いてこのパターンの実装を紹介したところ、はてブに「アプリにSecret持たせてるの?信じられない」みたいなコメントもついてました。
多くの開発者がそういう意識になってくれたら良いことなんですが、実際はこういう実装を選択する事案が存在します。
言い分としては
- Public Client 向けの JS SDK / モバイルアプリのSDKが用意されているからトークンとるとこまでできちゃう
- Backend Server に "ユーザー識別子だけ" を送ってログインさせたらダメなことぐらい知ってる。Access Token をバックエンドに送って検証すればいいって LINE のドキュメントにも書いてた
というところですが、 "とりあえずトークンを Backend Server に渡せれば良い" ぐらいで考えていると Backend Server とのやりとりの部分であれこれされたり、認可サーバーの制限によって "Confidential" な Client 向けの機能を利用できなくなる可能性もあるので気をつけましょう。
"Backend Serverに任せる" ならモバイルアプリやSPAは "User-Agent" 相当となり、全体としては "Confidential" となる
次に、認可サーバー/リソオースサーバーとのやりとりを Backend Server に任せる パターンです。
前提として、モバイルアプリやSPAとBackend Serverの間にセッションが確立しており、Client は認可リクエストのURLにリダイレクトするだけ、認可レスポンスのパラメータを Backend Server に送るだけです。
このような場合、 Client の役割としては User-Agent 相当となり、全体で見ると Backend Server が "Confidential" な Client となります。
Twitterでも触れられていましたが、金融機関向けのプロファイル(FAPI)でもこの方式について触れられており、リソースアクセスの内容によってはこの方式でセキュアな実装を目指すことが必要でしょう。
"Credentialed" at OAuth 2.1
重要 : このCredentialedという定義はOAuth 2.1のDraftから消え去りました。忘れてください。
以前から、Public Client に Client Secret を埋め込むのがダメなら、インストール時とかに動的に登録させたら良いじゃない みたいな話がありました。
現在仕様策定中の OAuth 2.1 では、新しく "credentialed" という Client Type が定義されています。
draft-ietf-oauth-v2-1-00 - The OAuth 2.1 Authorization Framework
"credentialed": Clients that have credentials and their identity has been not been confirmed by the AS are designated as "credentialed clients"
クレデンシャルは持っているけど認可サービスから存在を確認されていないクライアント とあります。
例を挙げると、モバイルアプリのインストールインスタンス毎に Client を登録を要求し、認可サーバーが ClientID/ClientSecret を発行します。
この場合、既存の "Public" な Client ができなかったクライアント認証が可能であり、発行されるトークン類もその Client 単位となります。
上で紹介した Backend Server を利用するようなリソースアクセスではなく、ネイティブアプリで完結する処理に利用することで、比較的簡単に "他の端末からは利用できないような制限" を施すことができるでしょう。
いわゆる Dynamic Client Registration の利用となりますが、実際に Dynamic Client Registration を考えると 静的な開発者登録からの Client 登録に比べて "未確認な状態" からの Client 登録となるため、なかなか実プロダクトでの使いどころは思い浮かばないかもしれません。
しかし、例えばプラットフォーム、iOSやAndroidのインストール時の機能として Dynamic Client Registration の要求を行い、そのリクエストが開発者が検証可能(開発者IDが含まれてプラットフォームにより署名されているJWTなど)であった場合、このような "Credentialed" なクライアントの可能性も見えてくるのではないかと思います。
OAuth 2.1 の現在の仕様(Draft)では "クライアント認証をできるときはする、Confidential や Credentialed な場合" ぐらいしか書いてありませんが、今後ユースケースなどが議論されることを期待しています。
まとめ
- OAuth 2.0 の Client Type について整理した
- Backend Server が絡む場合についても整理した
-
OAuth 2.1 では Credentialed という Client Type の定義もある忘れてください
少しずつ OAuth の基本知識を増やしていきましょう。
ではまた。
Discussion