OAuthのstateパラメータの意義をもう少しかみ砕いて理解する

先日OAuthのセキュリティについて勉強する機会があり、RFCを読んでみたり外部の解説サイトを拝見したりしていました。ただ、文字では何となく理解できるものの、自分で認可サーバを作った経験もないので、今一つ腹落ちせずな状況で、システムからやや離れた事例で考えると理解しやすいかな?とも思い、少し整理したいと思います。

OAuthの流れ

身近な例、ということで握手会に行くときのケースで考えてみました。ここではオンライン上のやり取りではなく、F2Fですが実際それなりに煩雑な手続きが必要で、割と近いかなとも思います(若干認証の流れの方に合わせている部分もあります。)

  • 握手会の参加者:Resource Owner
  • 会場運営/警備員:Client
  • アイドル事務所:Resource Server/Authorization Server

という登場人物です。会場運営(Client)はあくまで場の管理をする立場で、リソース(握手イベント)自体はアイドル事務所(Resource Server)が提供しているイメージです。

f:id:ybnskk:20201102061234p:plain

  1. 参加者は握手券の「予約券(=まだ握手できる権利はない)」を持って会場に行きます。
  2. 参加者が予約券しか持っていないので、警備員(Client)に受付に行くように言われます。
  3. 参加者は受付(Authorization server)に予約券と、本人確認書類を持って行き、「自分が推しのXさんの握手会の予約者本人である」ことを証明します。
  4. 受付は参加者に「Xさんとの握手券」を渡します。
  5. 参加者は握手券を持って会場に戻り、警備員(Client)に渡します。
  6. 警備員はスタッフ(Resource Server)に握手券を渡します。
  7. スタッフは握手券に確認済みの印をつけて警備員に渡します。

最終的に、警備員(Client)が確認済みの握手券(アクセストークン)を持って、参加者が握手したいアイドルの握手スペースをオープンし、晴れて握手ができる、という流れです。

セキュリティリスク

では、ここで考えられるセキュリティリスクとはどんなものでしょうか。今回は下記のリスクと対策についてまとめていきたいと思います。

Cross-Site Request Forgery(CSRF

CSRFはユーザに意図しないリクエストをサーバに送信させる攻撃です。OAuthの認証フローにおいては下記のような流れが想定されます。

f:id:ybnskk:20201102061403p:plain

  • 悪意あるユーザは受付で自分の握手券を入手します(①~④)。
  • 何らかの方法で標的のユーザと自分の握手券を入れ替えます。
  • 握手券は「悪意あるユーザが持っている握手券」として認証されます(⑤~⑦)。

一見標的のユーザも握手ができるので問題はなさそうですが、例えばユーザは推しのXさんにだけ自分の秘密を話したとします。対面の握手会では顔が見えているのでやや想像しにくいですが、ユーザは握手券の情報のみから判別すると「悪意あるユーザ」となります。次回、悪意あるユーザがXさんに会いに行くと、Xさんからすると同じ悪意あるユーザとして認識されるので、もしかすると前回聞いた秘密を悪意あるユーザに話してしまうかもしれません。

このようなケースもユーザにとってはセキュリティリスクであり、握手券を発行した相手と握手券を持ってきた人が同一人物か確認する必要があります。

stateパラメータの利用

その対策として実装されているのが「state」パラメータです。

f:id:ybnskk:20201102061455p:plain

  • ユーザB(悪意あるユーザ)が受付で認証をする際、受付はBさんの情報といっしょにBさんのstateパラメータを保存します(①~④)。
  • ユーザBがユーザA(標的のユーザ)に自分の握手券を何らかの方法で渡しアクセスさせます。
  • しかし、利用しているstateパラメータはユーザBのものであるため、ユーザAは利用できずエラーとなります。

stateパラメータによって、トークンエンドポイントにおいて、codeを受け取った人とトークンをリクエストする人が一致しているかを確認することができます。