概要
本投稿はDraft 8の仕様 を参照しながら書きました。
誰のための仕様?
インターネットに接続されているが、簡単な入力方法を持たないOAuth Client.
もう少し詳しく書くと、
- HTTPSのリクエストを外部に送ることができる
- URIとコードを表示もしくは別の方法でユーザーに伝えられる
例えば?
スマートTV, メディアコンソール, デジタルフォトフレーム, プリンタ等のいわゆる "constrained device"
何ができるようになる?
OAuth の認可処理
どうやって?
スマートフォンのようなセカンダリデバイス上で認可リクエストへの許可を実行するようにユーザーに指示する。
"constrained device" とセカンダリデバイスの間の通信は不要。
認可フロー
全体の流れ
- (A) Device AuthN Request : Device が AuthZ Server に Client IDを送る
- (B) Device AuthN Response : AuthZ Server は Verification Code(Device Verification Code), User Code(End-User Verification Code), Verification URI を返す
- (C) User Interaction : Device は End User に セカンダリデバイスで Verification URI にアクセスし、User Code を入力してアクセスを許可するよう促す
- (D) User Interaction : End User は Verification URI へのリクエストにて、ユーザー認証、アクセス許可、User Codeの入力を行う。AuthZ Server は User Code を検証
- (E) Device Access Token Request : End User がごにょってる間、 Device は AuthZ Server にポーリングしてアクセス許可が終わったか問い合わせる。具体的には Verification Code と Client ID を送る。
- (F) Device Access Token Response : アクセス許可が完了したら、 AuthZ Server は Verification Code を検証、 Access Token を返す
Device AuthN Request / Response
End User に表示する値を取得するやりとり。
# Request to Device AuthZ Endpoint
POST /device_authorization HTTP/1.1
Host: server.example.com
Content-Type: application/x-www-form-urlencoded
client_id=459691054427
# Response
HTTP/1.1 200 OK
Content-Type: application/json
Cache-Control: no-store
{
"device_code":"GMMhmHCXhWEzkobqIHGG_EnNYYsAkukHspeYUk9E8",
"user_code":"WDJB-MJHT",
"verification_uri":"https://www.example.com/device",
"verification_uri_complete":"https://www.example.com/device?user_code=WDJB-MJHT",
"expires_in" : 1800,
"interval": 5
}
詳細の説明は省略する。
Device Access Token Request / Response
アクセス許可が終わったタイミングでアクセストークンを要求する部分。
# Request to Token Endpoint
POST /token HTTP/1.1
Host: server.example.com
Content-Type: application/x-www-form-urlencoded
grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Adevice_code
&device_code=GMMhmHCXhWEzkobqIHGG_EnNYYsAkukHspeYUk9E8
&client_id=459691054427
成功時のレスポンスは RFC6749 で定義されているものと同じ。
追加のエラーコードとして、
authorization_pending
slow_down
expired_token
が用意されているのが独自な部分。
このリクエストがガンガン来るってことなので、Token Endpoint 頑張れ。
想定されているセキュリティリスクと対策
言うてもOAuthなので、攻撃者と被害者、アカウントをどうこうの部分に注目して見る。
User Code Brute Forcing
攻撃者が、第3者の User Codeを総当たりで入力し、自らのアカウントと第3者のデバイスを紐付けてしまうリスクがある。
OAuth の脆弱性の話ではもはや定番とも言える"攻撃者のアカウントを捧げちゃうリスク"であるが、どうしても軽視しがちなので書いておく。
リスクは被害者のアクティビティを知ることによるプライバシーの問題に限らず、紐付けられたアカウントができることが増えた時、つまり被害者のデバイスをリモートで操作できるような権限を攻撃者に与えてしまう事態にもなりかねない。
Device AuthN Response に含まれる Verification URI について、仕様の中のサンプルなどでは共通のものを用いている。
手動でブラウザに入力させたりするために、短く、覚えやすくすべきだみたいな感じなので、しょうがないかもしれないが、このような実装では、Verification Code に紐づくものが User Code のみなので、上記リスクが発生する。
対策としては、User Code の十分なエントロピー、試行回数制限などが挙げられているが、ユーザービリティとの兼ね合いで正直この辺りはどんな仕様で行くか悩みそうである。
それ以外の対策として、例えば Verification URI をQRコードで表示するような実装をする場合、Verification Code 毎に Verification URI を変えることも可能だろう。
その場合、攻撃者は第3者のデバイスとの紐づけに用いられる User Code 入力画面にたどり着くのが困難、かつ User Code の検証も容易(万が一別の有効な User Code を突っ込んでも弾ける)なため、このリスクへの対策として良さそう。
MLでこの辺りの議論がないか確認する必要がありそう。
Remote Phishing
User Code Brute Forcingとは対照的に、攻撃者が自らの管理下にあるデバイスと第3者のアカウントを紐づけてしまうリスクがある。
メッセージ系ツールで言葉巧みに Verification URI に誘導し、被害者のセッション上で User Code を入力させることができたら成功である。
Verification URI に User Code を含む場合はワンクリックになるので、さらに危険。
対策としては、ユーザーに対して、認可対象のデバイスを表示するなど、何が起ころうとしているのかを伝える仕組みが必要。
ブラウザの認可フロー内でコードを表示しつつ、手元のデバイスで同じコードが表示されていることを確認すると言う対策も書かれているが、厳しそう。
認可フローへのつなぎがあるので、User Code の有効期限を長くしたいところだがフィッシング対策としては短い方が良いのが悩みであるし、新鮮な User Code を送り込んでくる攻撃者には通用しない。
#ユーザビリティについて
利用可能な文字列などが書いてあり、参考になる。が、詳細は省略
感想
- デバイスが担う部分のフローはシンプル、ユーザーインタラクションのところはあまり書かれてないけど、今後もう少し膨らむのかも
- セキュリティリスクへの対策については、微妙なところが多いので先行サービスの実装にならう流れになりそう