はじめに
皆さんこんにちは!新卒2年目エンジニアの細川です。
今回はOAuth2.0について学ぶ機会があったので、OAuth2.0の中で定められているいくつかのグラントタイプの中で最も重要そうな認可コードグラントについて少しまとめてみたいと思います!
OAuth2.0、認可コードグラントについて
そもそもOAuthってなに?っていう方に簡単に説明すると、OAuthというのは権限を渡すための仕組み、標準仕様のことです。ユーザーがアプリAとアプリBを利用して、アプリAがアプリBのデータを利用したい場合に、ユーザーに代わってアプリBにアクセスするための権限をアプリAに渡すための仕組みです。例えば、予約アプリで予約する場合を考えてみると、カレンダーアプリ(Google カレンダーなど)に予約の予定を追加してくれるものとかありますよね。これは予約アプリにGoogleカレンダーへのアクセス権限を渡しているということになります。予約アプリでなくても他アプリのデータにアクセスするような場合に、以下の画像のような画面を見ることがよくあるかと思います。
OAuth2.0はこのように権限を渡すためのものです。
OAuth2.0ではいくつかグラントタイプというものが定義されていて、グラントタイプによって処理の流れなどが異なります。最も使われているのがおそらく認可コードグラントだろうということで今回は認可コードグラントについて触れていきたいと思います!
認可コードグラントは他のグラントタイプに比べると若干流れが複雑ですが、その分セキュアでよく使われているみたいです。また、PKCE(ピクシー)という拡張仕様を用いることで、よりセキュリティを担保できるとのことなので、認可コードグラント+PKCEの場合の流れについてもまとめたいと思います!
認可コードグラントの流れについて
では、認可コードグラントの実際の処理の流れについてです!今回は先ほど例で挙げた予約アプリでGoogleカレンダーにアクセスする場合について考えてみます。スマホに予約アプリを入れている状況を想像してみてください。
以下に処理のシーケンス図を示します。(文字が小さいので拡大してくださいすみません)
図を追うと一通りの流れはわかると思うので、ちゃんと流れを知りたい方はぜひ拡大して読んでみてください!
この処理の流れを大きく3つに分けると、以下の3つになります
step1. 認可コードの取得
step2. アクセストークンの取得
step3. リソースへのアクセス
実際にGoogleカレンダーへのアクセスはstep3で行うこととなります。
step2, 3については他のグラントタイプでも同じ流れになるはずです。基本的にOAuthでは認可サーバーからアクセストークンを受け取ってリソースにアクセスできるようになります。
step1で認可コードを取得していますが、これが認可コードグラントの大きな特徴といえます。グラントタイプによっては上記図の9. 委譲への同意が行われた時点でアクセストークンを返すようなグラントタイプ(インプリシットグラントなど)もありますが、それに比べて一段階認可コードを挟むことによってよりセキュアなやり取りができるようになっています。インプリシットグラントの違いについては同期の龍ちゃんのブログを参考にしてみてください。
また、2.でstateを生成して受け渡ししたり、事前に登録しているclient_idなどを用いてクライアント(予約アプリ)の認証を行うなど、要所要所でやり取りする相手を確認しながら処理を行っていることも認可コードグラントの特徴として挙げられるそうです。
入れ替わりの危険性
認可コードグラントはセキュアなグラントタイプであるというお話はしましたが、実は上のシーケンス図の場合、別のアプリに認可コードが流出してしまう危険性があります。
ポイントは11. カスタムスキームによるアプリ起動の部分です。この部分でブラウザがカスタムスキームに対応したアプリを起動してくれるのですが、実はカスタムスキームは重複が禁止されていません!そのため、同じカスタムスキームを持つ別アプリが起動してしまう可能性があります。
別アプリが起動してしまうと、そのアプリに認可コードが渡ってしまい流出の危険性があります。
別アプリがハッキング目的だった場合、そのままアクセストークンを盗まれてリソースを使われてしまう可能性もあります。
認可コードグラント+PKCEについて
上記で述べたように途中でアプリが入れ替わってしまった場合にその入れ替わりに気づけるための仕組みがPKCE(Proof Key for Code Exchange「読み:ピクシー」)です。
カスタムスキームの重複による入れ替わりは、OSのバージョンによって挙動などが異なり、非常に防ぐのが難しいため、入れ替わられることを前提に入れ替わられていたら、途中で処理をやめよう!みたいな仕組みです。
PKCEはやり取りの際に追加で以下の3つのパラメータを利用します。
code_challenge
の計算方法としては、SHA256のハッシュ値を計算したのちにbase64エンコードを行ったものが一般的なようです。SHA256についてはこちらなどを参考にしてみて下さい。
基本的には計算後の値から計算前の値が逆算できないような計算方法がよさそうです。
以下にPKCEを組み合わせた場合のシーケンス図を示します。(すみません相変わらず文字が小さいです)
先ほどのシーケンス図と異なる場所をオレンジ枠で囲っています。
まずは、認可リクエストを送る際にcode_challenge
(変換後)とcode_challenge_method
を追加で送信しています。送られた認可サーバーがそれらを保存しておきます。
その後、12. でトークンリクエストを送信するときにcode_verifier
(変換前)を送信し、13で. 検証をします。
code_verifier
は予約アプリ内で生成するランダムな文字列なので、万が一、11. で起動するアプリが入れ替わっても、別のアプリはcode_verifier
の値を知ることができません。
よって、アプリが入れ替わっていた場合は13. の検証がうまくいかず、別のアプリではアクセストークンを取得できなくなります。
stateとcode_verifierの違い
ここまで読まれた方なら、state
とcode_verifier
ってめっちゃ似てない!?と思った方もいると思います。
どちらもランダムな値を生成して入れ替わりを検知する目的で使われるものという共通点はあります。しかし、それを検証する場所が違います。
state
は10, 11. で予約アプリに返して、予約アプリ側で検証します。それに対してcode_verifier
は変換前と変換後の値をどちらも認可サーバーに送信して、認可サーバー側で検証を行います。検証する場所やタイミングが異なり、検知できる入れ替わりのタイミングや対象なども異なるため、そのあたりの違いはあります。ただ、大きな目的として相手の入れ替わりを検知するというものは共通点かと思います。
まとめ
- 認可コードグラントはOAuth2.0で定められているグラントタイプの中でもセキュアであり、よく利用されている。
- 認可コードグラントでは入れ替わりの可能性もあるため、検知できる仕組みとして拡張仕様であるPKCEを利用する。
おわりに
今回、OAuthの中でも(きっと!)一番重要な認可コードグラントについてまとめてみました。
読み始めた時点ではそもそ認証・認可の違いなども曖昧でOAuthなにそれ状態だったので、第一歩は踏み出せた気がします。
今回まとめた中でも間違っているところ等あると思いますが、その時は優しくご教授いただけると嬉しいです(笑)
参考書籍
今回参考にさせていただいた書籍は以下になります!
大変わかりやすかったのでぜひ皆さんも購入して読んでみてください!