こんにちは、サイオステクノロジー武井です。今回は、ちょっと難解なOAuthをわかりみ深く説明してみたいと思います。本記事は、私がOAuthを理解するまでの備忘録みたいなものになり、説明が至らないこと多々あると思いますが、生暖かい目で見守って頂けますと幸いです。
全4回シリーズでお届けする予定で、今回は最後の第4回目となります。
- その1:OAuthってなに?
- その2:アクセストークンとリフレッシュトークン
- その3:OAuthを認証に使うことの危険性
- 今回はこちら → その4:stateパラメーターによるCSRF対策
stateパラメーターとは?
stateパラメーターは、CSRF(クロスサイトリクエストフォージェリ)対策で付与します。CSRFとはユーザー本人がいとしないリクエストを、悪意のある第三者によって強制する攻撃のことです。だいぶ昔には、mixiの「はまちちゃん」で有名になりましたが、OAuthやOpenID Connectにも同様のリスクがあります。その対策がstateパラメーターになります。ただ、stateパラメーターで対策するのは、「なりすまされ」というのであって、ここが今までのCSRF対策とイマイチ違いがわかりにくい点になります。(少なくとも私は理解に苦しみました^^;)
stateパラメーターの説明
stateパラメーターのない世界と、ある世界ではどのように違うのかを説明することで、stateパラメーターの有効性を説明します。とあるシステムを例に上げることとします。そのシステムの登場人物は以下のとおりとなります。
ストレージサービス・・・クラウド上のオンラインストレージサービスです。ユーザーは自分の領域に任意のファイルを格納することが出来ます。 | |
サービスA・・・ストレージサービスを利用するサービスです。OAuth認証を用いて、ユーザーにストレージサービスを利用させます。 | |
Aさん・・・サービスAの正規な利用者です。 | |
悪い人・・・ユーザーAさんに対してCSRF攻撃を行おうとする攻撃者です。 |
stateパラメーターのない世界
stateパラメーターのない世界では、どのような悪いことが起こるのかを説明します。
まず、以下のようなシステムを想定します。ストレージサービスは外部にAPIを公開しており、そのAPIでファイルをアップロードできます。そしてAPIの認証はOAuthで行います。サービスAはOAuth認証を用いて、ユーザーがサービスAにアップロードした画像をストレージサービスにもアップロードします。悪い人は、まず、サービスAにアクセスして、OAuth連携を開始します。
悪い人は、ストレージサービスの認可画面にリダイレクトされます。「はい」をクリックします。
すると、認可コードをクエリパラメーターに付与した、サービスAへのリダイレクトが発生します。しかし、悪い人は、ここで、リダイレクト先のURLだけ取得をし、サービスAにリダイレクトさせないようにします。この実現方法は色々ありますが、独自のHTTPクライアントのプログラムを開発して、Locationヘッダからリダイレクト先のURLだけを抜き取り、実際のリダイレクトはさせないようにすればよいと思います。
悪い人は、先程取得したURLをメールなどの手段でAさんに送付して、AさんにそのURLにアクセスさせます。すると、アクセストークンを取得する主体は、悪い人からAさんに移り、悪い人のアクセストークンを取得するプロセスは、今後、Aさんのセッションで行われることとなります。ここがキモです。
サービスAは、認可コードをストレージサービスに渡して、アクセストークンを要求します。
ストレージサービスは、悪い人のストレージにアクセスするためのアクセストークンをサービスAに返します。なぜそうなるかというと、アクセストークンを取得するために発行された認可コードは、悪い人によって発行されたものだからです。
そして、そのアクセストークンは、ユーザーAのデータベースに格納されます。なぜそうなるかというと、認可コードをサービスAに渡したのは、他ならぬAさんだからです。
つまり、Aさんは、悪い人のアクセストークンを取得し、悪い人のストレージに自由にアクセスできるようになりました。他人のストレージを自由にアクセスできるわけですから、あまり害はないように思えますが、ここで一番まずのは、Aさんが知らない間にこのような状況に陥ってしまったことです。これは、「乗っ取り」ではなくて「乗っ取られ」といわれるもので、例えば、他の人に漏らしたくないような情報を自分のフォルダにアップロードしたつもりが、実は悪い人のフォルダに知らない間にアップロードしていることになり、悪い人はAさんのプライベートを見ることが出来てしまうわけです。
stateパラメーターのある世界
stateパラメーターがあると、先程のような被害を防ぐことが出来ます。先程のケースで、stateパラメーターを付与した場合にどの様になるかを説明してみます。
悪い人は、まず、サービスAにアクセスして、OAuth連携を開始します。ここまでは、先程と一緒です。
悪い人は、ストレージサービスの認可画面にリダイレクトされます。先ほどと違うのは、サービスAがリダイレクト先のURLのパラメーターにstate=xyzという値を付与していることです。さらに、このとき、サービスAは、このstateの値を悪い人のセッションに紐づけます(Javaでいえば、request.
すると、認可コードをクエリパラメーターに付与した、サービスAへのリダイレクトが発生します。しかし、悪い人は、ここで、リダイレクト先のURLだけ取得をし、サービスAにリダイレクトさせないようにします。先ほどと違うのは、ストレージサービスは、1つ前のプロセスで渡されたstateパラメーターをそのまま同じように、リダイレクト先のURLに付与しているところです。
先程と同様に、悪い人は、先程取得したURLをメールなどの手段でAさんに送付して、AさんにそのURLにアクセスさせます。
「stateパラメーターのない世界」と決定的に違うのがこのプロセスです。サービスAは、URLに付与されているstateパラメーターと、アクセスしてきたユーザーのセッションに格納されているstateパラメーターを比較して、一致していなければ不正なアクセスとして、処理を中断します。認可コードを取得したのは悪い人なので、stateパラメーターは悪い人のセッションの中に格納されていますが、認可コードをもとにアクセストークンを要求したのはAさんです。もちろん、Aさんのセッションの中には、stateパラメーターの値が入っていないので、下記のように不一致となります。このような理路により、CSRF攻撃を防御することが可能です。
まとめ
いかがでしょうか?4回の連載でOAuthについて説明しました。至らぬ点多々あったかもしれませんが、もし今回の説明がOAuthに対する理解の一助になれば幸いです。