【連載】世界一わかりみの深いOAuth入門 〜 その2:アクセストークンとリフレッシュトークン 〜

こんにちは、サイオステクノロジー武井です。今回は、ちょっと難解なOAuthをわかりみ深く説明してみたいと思います。本記事は、私がOAuthを理解するまでの備忘録みたいなものになり、説明が至らないこと多々あると思いますが、生暖かい目で見守って頂けますと幸いです。

全4回シリーズでお届けする予定で、今回は第2回目となります。

  1. その1:OAuthってなに?
  2. 今回はこちら → その2:アクセストークンとリフレッシュトークン
  3. その3:OAuthを認証に使うことの危険性
  4. その4:stateパラメーターによるCSRF対策

アクセストークンとは?

今回は、「その1:OAuthってなに?」であげたOAuthの4つの特徴のうち、以下の2つ(3と4)を説明致します。

  1. 従来のID・パスワードベースとは異なるトークンベースの認証
  2. トークンには限られた権限だけを与えられているので、万が一トークンが盗まれても被害が少ない
  3. 今回はこちら →  認可コードフローなどによりトークンを安全に取得
  4. 今回はこちら → トークンには有効期限が設定されており、万が一トークンを盗まれても有効期限過ぎると使えないので、セキュア

アクセストークンとは「その1:OAuthってなに?」でもご説明したように、リソースサーバーからリソースを取得するための通行手形のようなものなのです。今回はそのアクセストークンをちょっとだけ掘り下げて説明できればと思います。

アクセストークンは、OAuthの仕様では、その形式を定めておりませんが、主に以下の形式を取ります。

タイプA

アクセストークンの中にアクセストークンに関する情報を内包せず、やり取りされる情報はアクセストークンを一意に識別する識別子のみで、アクセストークンに関する情報はデータベースなどに保存する。

タイプB

アクセストークンに関する情報をアクセストークンの中に内包する形式

ではタイプAとタイプBそれぞれ説明していきたいと想います。

タイプA:アクセストークンの中に情報を含まない場合

まずはタイプAのパターンについて説明します。タイプAでどのようにアクセストークンを取得して、リソースサーバーに渡すのかを図を用いて紙芝居的に説明します。

処理の流れ

ここで認可コードフローをちょっとおさらいします。「その1:OAuthってなに?」で説明した認可コードフローでアクセストークンを取得するためには、認可コードをFacebook(認可サーバー)にリクエストしないとダメなのでした。なので、発行された認可コードを渡します。


認可コードを要求されたFacebookは、自身が発行してデータベースに登録した認可コードとその有効期限を確認し、問題がなければ、Twitterにアクセストークンを返します。アクセストークンを発行したFacebook、アクセストークンを受け取ったTwitterの両方は、ユーザーIDとアクセストークンが紐付いた情報をデータベースに登録します。


Aさんは、Twitterにつぶやきます。


TwitterはAさんのつぶやきを画面に表示します。それと同時に、Facebookにも同様の投稿を行います。この際、Facebookには、投稿の内容と同時に、アクセストークンを渡します。アクセストークンは、Twitterへのログインユーザーをキーにデータベースから取得します。


アクセストークンを受け取ったFacebookは、データベースからアクセストークンを検索して、もし見つかったら、それに紐づくユーザーIDで、Facebookに投稿します。これで、連携完了です。


では先程御説明したように認可サーバーとリソースサーバーが別々だった場合はどうでしょうか?


認可サーバーとリソースサーバーが別々になった場合を考えてみます。以下は認可サーバーはマイクロソフトが提供するAzure Active Directory、リソースサーバーはFacebookという構成になります。この構成で、もう一度認可コードをリクエストするところから流れを追ってみたいと思います。なので、発行された認可コードを渡します。


認可コードを要求されたAzure Active Directoryは、自身が発行してデータベースに登録した認可コードとその有効期限を確認し、問題がなければ、Twitterにアクセストークンを返します。アクセストークンを発行したAzure Active Directory、アクセストークンを受け取ったTwitterの両方は、ユーザーIDとアクセストークンが紐付いた情報をデータベースに登録します。


Aさんは、Twitterにつぶやきます。


TwitterはAさんのつぶやきを画面に表示します。それと同時に、Facebookにも同様の投稿を行います。この際、Facebookには、投稿の内容と同時に、アクセストークンを渡します。アクセストークンは、Twitterへのログインユーザーをキーにデータベースから取得します。


さて、ここからが問題なのですが、アクセストークンを受け取ったFacebook(リソースサーバー)はそのアクセストークンが正しいものかどうか確かめたいので、Azure Active Directory(認可サーバー)のアクセストークンと比較したいですが、通常Azure Active DirectoryはFacebookとは全然異なるネットワークにあるため、直接データベースの中を見ることができません。

タイプB:アクセストークンの中に情報を含む場合

次は、先程タイプAで出た問題を解決するためのタイプB(アクセストークンの中に情報を含む場合)の説明をしたいと思います。一般的にはこの問題を解決するための手段として「JSON Web Token」を用いることが多いのですが、その前に前提知識として以下のことを説明致します。

  • 秘密鍵暗号方式
  • 公開鍵暗号方式
  • 公開鍵暗号方式による改ざん防止
  • 公開鍵暗号方式による身分証明

秘密鍵暗号化方式

お互いに同じ暗号化の鍵を共有して、暗号・複合する方式です。暗号化・復号化に使う鍵は同じです。鍵を相手に渡すときは、盗聴されないよう、郵送などの手段を取る必要があります。

公開鍵暗号化方式

公開鍵暗号化方式は、暗号に使う鍵と、復号に使う鍵がそれぞれ異なる暗号化方式です。Bさんの公開鍵を取得して、Aさんは、その公開鍵で文書を暗号化します。その文書を受け取ったBさんは、自分の秘密鍵で復号します。

 

秘密鍵暗号化方式だと、例えば下記例のようにAさんが、BさんとCさんとDさんに暗号化した文書を渡したい時に、郵送など絶対に盗聴されない手段で、それぞれの人にAさんの秘密鍵を渡さないといけません。非常に面倒です。

 

公開鍵暗号化方式を使えば、インターネットなどで公開されているBさん、Cさん、Dさんの公開鍵を取得して、それで暗号化すればOKです。公開鍵が通信経路で盗聴されたとしても、秘密鍵さえ漏洩しなければ、暗号化した文書は安全です。公開鍵暗号化されたものは、秘密鍵でしか復号できないからです。

 

公開鍵暗号化方式による改ざん防止

公開鍵暗号化方式を使えば、暗号化した文書が通信経路の途中で改ざんされていないかどうかを検知することが可能です。

 

改ざんされると以下のような結果になり、改ざんされたことを検知できます。

公開鍵暗号化方式による身分証明

電子証明書を使えば、インターネットの世界で身分証明を行うことが出来ます。リアルな世界の印鑑証明みたいなものです。市役所に相当するのが認証局になります。

 

SIOS商店が取得した電子証明書は、俗にいうSSL証明書になります。SIOS商店のネットショップに、IDとパスワードを送る仕組みは以下のとおりです。

JSON Web Token

JSON Web Tokenとは、JSONに電子署名を行い、必要に応じてそのJSONの検証を行い、認証可否を決定する仕様です。OpenIDやOAuthなどに用いられている標準的な仕様です。

JSON Web Tokenの仕様に従って作成されたトークンは以下のようになっています。

長い文字列ですが、構成としては、ヘッダー、ペイロード、ヘッダーとペイロードをピリオドでつないで署名したものの3つをピリオドでつなげたものです。つまり以下のような感じです。

[ヘッダー].[ペイロード].[ヘッダーとペイロードをピリオドでつないで署名したもの]

ヘッダー、ペイロードをそれぞれ説明します。

■ ヘッダー

署名アルゴリズムとトークンのタイプを定義します。具体的には以下のようなJSONになります。

{ 
    “alg”: “HS256”, 
    “typ”: “JWT”
}

これは署名アルゴリズムはHS256、トークのタイプがJSON Web Tokenであることを表しています。トークンのタイプは他にもJWE(JSON Web Encryption)と言うものがあり、これは暗号化まで仕様として定義しているようです。しかしながら、今回は暗号化は行わず、あくまで署名だけですので、SSL等で暗号化することは必須となります。

■ ペイロード

JSON Web Tokenでやり取りするデータ本体です。例えばユーザー名だったり、認可情報だったり、ユーザーが自由に定義します。例えば以下のような感じです。

{ 
    “sub”: “ntakei”
}

これは、ユーザー名がntakeiのデータになります。ただ、何でも定義していいというわけではなく、幾つかのフィールド名はJSON Web Tokenの仕様によって予約されています。詳細はRFCを参照頂ければわかるのですが、例えば、expというフィールド名はトークンの有効期限として使われることが決まっているので、使ってはいけません。

次に、トークンを作成するまでの流れ、そしてそのトークンを検証するまでの流れを説明したいと思います。

認可サーバー側では以下のような流れでアクセストークンが作成されます。

 

リソースサーバーではアクセストークンを以下のような流れで検証します。

処理の流れ

だいぶ横道にそれましたが

「タイプB:アクセストークンの中に情報を含む場合」の処理の流れを説明したいと思います。

タイプAで認可サーバーとリソースサーバーが別れている場合は、リソースサーバー側でアクセストークンの確認ができませんでした。これをJSON Web Tokenにした場合の流れについて説明します。認可サーバーとリソースサーバーが別々になった場合を考えてみます。以下は認可サーバーはマイクロソフトが提供するAzure Active Directory、リソースサーバーはFacebookという構成になります。この構成で、もう一度認可コードをリクエストするところから流れを追ってみたいと思います。なので、発行された認可コードを渡します。


認可コードを要求されたAzure Active Directoryは、自身が発行してデータベースに登録した認可コードとその有効期限を確認し、問題がなければ、TwitterにJSON Web Token形式のアクセストークンを返します。タイプAと違うのは、Azure Active Directory側(認可サーバー)側にアクセストークンを保存していません。


実は「手順その8」では先にご説明した以下の手順に基づき、認可サーバー側で以下のようにアクセストークンが生成されています。


ということで、アクセストークンが無事作成されたので、まず、Aさんは、Twitterにつぶやきます。


TwitterはAさんのつぶやきを画面に表示します。それと同時に、Facebookにも同様の投稿を行います。この際、Facebookには、投稿の内容と同時に、アクセストークンを渡します。アクセストークンは、Twitterへのログインユーザーをキーにデータベースから取得します。


アクセストークンを受け取ったFacebook(リソースサーバー)は右図のような流れでアクセストークンが正しいかどうかを検証します


無事連携完了できました。タイプAと異なり、Facebook(リソースサーバー)は、JSON Web Token形式のアクセストークンを検証することで、Facebookは、Azure Active Directoryなど他のシステムにアクセスすることなく、アクセストークンを検証することができました!!

リフレッシュトークンとは?

本章ではリフレッシュトークンについて説明します。アクセストークンと同じくらいよく聞く単語かと思います。

アクセストークンは超短命(1時間程度)であり、短命であるがゆえに漏洩したときのリスクを抑えています。しかし、アクセストークンの有効期限を過ぎた場合に認可サーバーに再認証してもう一度アクセストークンを取得するのは非常にユーザビリティに欠けるため、リフレッシュトークンを認可サーバーに送るだけでアクセストークンを再取得できます。

この説明ではなかなかイメージがつかないと思いますので、ここでもリフレッシュトークンがない場合とリフレッシュトークンがある場合をくらべて、どんな点が良くなるのかを比較してみたいと思います。

リフレッシュトークンがない世界

ではまず、リフレッシュトークンがない世界ではどのような不便なことがおこるのか説明します。

以下の図は、「OAuthをざっくり説明」で説明したもので、すでにアクセストークンを取得済みであることを表した図です。これをベースに説明します。

AさんはTwitterに「白金なう」とつぶやきます。


Twitter(クライアント)からFacebook(リソースサーバー)にアクセストークンが渡されて、TwitterはFacebookのAPIを実行することができて、TwitterのつぶやきがFacebookにも反映されます。


もう一度Twitterにつぶやいてみました。でも今度はアクセストークンの有効期限が切れてエラーになってしまいました。


しょうがないので、もう一度Facebook(認可サーバー)での認証からやり直してアクセストークンを取得するところからやり直そう。。。って事になります。でも、アクセストークンが切れるたびにこんな事するのめんどくさいですよね。なんとかしたいものです。

リフレッシュトークンがある世界

そこでリフレッシュトークンがある世界です。実はFacebook(認可サーバー)での認証が終わって、Facebookからアクセストークンが発行されると同時にリフレッシュトークンも発行されます。


ちなみに認可サーバーから返されるアクセストークンとリフレッシュトークンは以下のようなJSON形式であることが多いです。access_tokenのフィールドの値がアクセストークン、 refresh_tokenのフィールドの値がリフレッシュトークンです。

{
  “access_token”:“2YotnFZFEjr1zCsicMWpAA”,
  "token_type":"example",
  "expires_in":3600,
  "refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA",
  "example_parameter":"example_value”
}

アクセストークンとリフレッシュトークンを取得した状態でTwitterにつぶやいてみます。


通常通りTwitterにもFacebookにも反映されます。


アクセストークンの有効期限が切れてリクエストがエラーになってしまいました。


Twitter(クライアント)はリフレッシュトークンをFacebook(認可サーバー)に送ります。


リフレッシュトークンを受け取ったFacebook(認可サーバー)は、アクセストークンとリフレッシュトークンを再作成して、Twitter(クライアント)に返します。


新しく生成されたアクセストークンで再度Facebook(リソースサーバー)にアクセスします。今度はちゃんと正常にアクセスできました!!

 

ところで、リフレッシュトークンなんてめんどくさい仕組み使わずに、アクセストークンの有効期限をとても長く(例えば6ヶ月位とか)してしまえばいいのではないかなと思いますが、アクセストークンの有効期限を長くするのはNGです。アクセストークンは、以下のようにリソースサーバーにリクエストを送るたびにネットワーク上を流れます。ということはとても頻繁にネットワークを流れることになり漏洩のリスクに晒されているのです。

 

アクセストークンを盗んだハッカーは、容易にFacebookの情報を操作できてしまいます。有効期限が超長いからです。

 

でもアクセストークンの有効期限を短くしておけば、たとえハッカーに盗まれたとしても1時間後には使えなくなるので、悪用されるリスクが減るわけです。

 

リフレッシュトークンもアクセストークンと同じくネットワーク上を流れます。そしてリフレッシュトークンはアクセストークンよりも有効期限は長いです。ただ、リフレッシュトークンはアクセストークンよりもネットワーク上を流れる頻度が少ないので、漏洩のリスクが少ないので、有効期限は長くても比較的大丈夫なのです。

まとめ

いかがでしょうか?アクセストークンとリフレッシュトークンというものがイメージできたら幸いです。至らぬ説明多々あったかもしれませんが、生暖かい目で見守って頂けたらと思います。

次回は、OAuthを認証に使った場合の危険性について説明いたします。

【連載】世界一わかりみの深いOAuth入門 〜 その3:OAuthを認証に使うとこの危険性 〜

ご覧いただきありがとうございます! この投稿はお役に立ちましたか?

役に立った 役に立たなかった

12人がこの投稿は役に立ったと言っています。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です