OAuthを認証に使う危険性

本章では、OAuthを認証に使うことの危険性について説明します。これはある特性の条件下で発動します。Implicitフローを使っている。アクセストークンの発行元を検証しない。プロファイル情報APIによって得たユーザー情報を認証ユーザーとしている。この3つの条件が重なった時に、OAuth認証による危険性が発動します。

(スライドを指して)これも絵で説明します。実際にやってみましょう。何人か登場人物がいます。まずAさん。ここでは「格ゲーX」というアプリを想定します。この人は格ゲーXをやる善良な市民です。格ゲーXは、とあるゲームプラットフォームで開発された善良なスマホ用格闘ゲームで、格ゲーXの開発者も善良な開発者です。

ゲームプラットフォームは、ゲームを開発するためのプラットフォームです。LINEなどがけっこう有名だと思います。ゲームプラットフォームの上でゲームを開発すると、認証や認可を全部ゲームプラットフォームがやってくれて、ゲーム開発者はゲームの開発だけに専念できる利点があるので、こんなふうにしています。私はあまりゲーム開発には詳しくないんですが、概ねこんな感じだったと思います。

まずここで、この場合のOAuth認証はどういうものかについて説明します。これは先ほどの認可コードフローと同じで、ゲーム開発者はゲームプラットフォームに対して「OAuthをしたい」という申請をします。

そうすると、クライアントIDとクライアントシークレットと利用サービスが発行されます。(スライドを指して)この利用サービスのprofileは、ユーザーの情報を提供するAPIを利用したいので、ここでは仮にprofileとしています。

Aさんは、自分のスマホ内にインストールされている格ゲーXというアプリをやりたいので、ユーザー認証をします。なぜユーザー認証をするかというと、格ゲーXは対戦記録を保存したり、ネット上のユーザーと対戦をしたりするために必要なので、Aさんはゲームプラットフォームのほうにユーザー認証を要求します。

ユーザーIDとパスワードを入れて送信すると、ゲームプラットフォームはアクセストークンを生成して、事前に登録したリダイレクトURIのハッシュフラグメントに、アクセストークンを付与します。先ほど説明したImplicitフローです。リダイレクトURIのハッシュフラグメントにアクセストークンがくっついてきます。この格ゲーXはアクセストークンを取得します。

まだこの段階ではユーザーIDがわかっていません。格ゲーXはゲームプラットフォームにアクセストークンを送ります。

そのアクセストークンを送ったレスポンスはユーザー情報APIを叩いているので、このアクセストークンに紐づいたユーザー情報、ユーザーIDや名前がAさんであるということが返ってきます。

そうすると、ユーザーIDにa-sanが登録されます。ユーザー情報からユーザーIDがa-sanということがわかったので、ではユーザーID「a-san」を登録しましょう、と。ここで、Aさんは「Aさんです」ということを認証できたことになります。

OAuth認証によって情報が乗っ取られる仕組み

次に、今まで説明したOAuth認証によって、Aさんの情報が乗っ取られる流れを説明したいと思います。今度は、先ほどの登場人物に加えて、悪いゲーム開発者と、「悪ゲーX」という悪いゲームが登場しています。

まずは、悪ゲーXという悪いゲーム。これは善良なユーザーのアクセストークンを盗むためだけに開発したゲームです。そいつを開発した悪いゲーム開発者は、同じようにゲームプラットフォームにOAuthの申請をします。

するとクライアントIDと利用サービスが発行されます。

ここは同じで、Aさんはユーザー認証を要求します。Aさんはこの悪ゲーXがすごく悪いゲームだということをぜんぜん知りません。そして、ユーザー認証を要求します。

そうすると、ゲームプラットフォームのほうにリダイレクトされます。ゲームプラットフォームはアクセストークンを発行して、この悪ゲーXにアクセストークンを渡してしまいます。

そうしてアクセストークンをゲームプラットフォームに要求します。

ユーザー情報が返ってきます。この時、悪ゲーXはクラウド上のどこかのデータベースの中に、AさんのユーザーIDとアクセストークンを保存します。

そうすると、このフローの中で、悪いゲーム開発者もAさんに対して発行されたアクセストークンを盗めてしまうんです。悪いゲーム開発者は、クラウド上のデータベースの中に保存されたAさんのアクセストークンをゲットできてしまいました。

ここからが悪いゲーム開発者の出番です。悪いゲーム開発者は、今度はこの格ゲーXにユーザー認証を要求します。

そうすると、格ゲーX内でゲームプラットフォームの認証画面にリダイレクトされます。ここまでは同じです。

ユーザーIDとパスワードを入力しますが、この時にリダイレクトのURIにハッシュフラグメントがついていて、この中にアクセストークンが埋め込まれます。そして、先ほどアクセストークンを盗んだAさんのアクセストークンにペロッとリプレースします。

リプレースする方法はいくらでもあると思います。例えばスマホの中にHTTPのリクエストをフックするツールを自作して入れて、アクセストークンを入れ替えるなどもできると思います。そのように、リダイレクトURLのハッシュフラグメントについては、アクセストークンを盗んだAさんのアクセストークンに置き換えます。

盗んだAさんのアクセストークンを、ゲームプラットフォームに要求します。この盗んだAさんのアクセストークンは、ゲームプラットフォームの中にあるわけです。このアクセストークンに紐づいたユーザーはAさんだから、Aさんのprofile情報を返してしまいます。

すると、格ゲーXの中のデータベースの中に"user_id":"a-san"となって入れてしまって、これで悪いゲーム開発者はAさんになりすますことができるというわけです。

OAuth認証によるなりすましを防ぐ3つの方法

このOAuth認証によるなりすましを防ぐためには、3つの方法があります。アクセストークンの発行元を検証すること。認可コードフローを使うこと。最後にOpenID Connectを使うことです。アクセストークンの発行元を検証することについては、アクセストークンを発行した時に、アクセストークンを発行した先のクライアントIDを事前にゲームプラットフォーム、認可サーバーの中に保存しておきます。

例えばアクセストークンを送った時に、このアクセストークンは格ゲーXから送られてくるアクセストークンであるにもかかわらず、このアクセストークンを発行した先は悪いほうのゲームのクライアントIDで一致しないことにより、OAuth認証によるなりすましを防ぐのが1つの手段です。

残りの2つのうち、認可コードフローを使うものとOpenID Connectを使うものがありますが、時間の兼ね合いで割愛したいと思います。私のセッションは以上です。