OAuth(オーオース)

OAuth(オーオース)とは

oauth-story-history3

OAuth(オーオース)とは、RFC2749別システムで管理されているユーザー情報照会などのAPIを呼び出すためのフェデレーションの仕組みです。

資産管理アプリを使っていますでしょうか?銀行口座やポイントカードなどの様々なサービスと連携して、すべての資産を集計してくれます。これは、OAuthの一つです。金融サービスで認証し同意を得ることでユーザー情報を安全に取得し、そのユーザー情報を集計してくれているのです。

ログイン画面で『代わりにGoogleでログイン』とか見たことありますよね。これもOAuthの一つです。Googleで認証し同意を得ることでユーザー情報を安全に取得し、そのユーザー情報を基にログインを代行しているのです。

oauth-relationship2

OAuthとOIDCは一緒?

似たようなシーケンスにOIDC(Open ID Connect)という仕様があります。実質的に、OIDCはOAuthの後継にあたり、仕様を包含しています。

ちゃんとするとIDトークンなどはOIDCに含まれていたりしますが、本記事ではOAuthとOIDCを厳密に分けず、このOAuthを知る上での必要な知識の一部として解説していきます。

SAMLとOAuthの違いについて

oauth-story-token2

同じフェデレーション仕様にSAMLがありますが明確な違いがあります。SAMLはユーザー認証後にユーザー情報を暗号化して渡すという仕組みです。そのため、ユーザー情報を最新化したいときにはユーザー認証を行う必要があります。その一方で、OAuthではユーザー認証後にユーザー情報を渡すのではなくユーザー情報を取得するためのアクセストークンを連携します。OAuthで連携したシステムはアクセストークンを使えばシステム自身が判断して好きなタイミングで最新のユーザー情報を取得することができます。例えば、資産一括管理アプリなどでSAMLを使うと、月次に銀行などの各連携先に毎回ログインを求められるますが、OAuthを使うと月次に勝手にアプリがユーザー情報をかき集めてくれます。

SAML
OAuth

この仕組みを作るため、OAuthではトークンという概念があります。トークンには3つあり、IDトークンとアクセストークンとリフレッシュトークンです。

  • IDトークンは、識別情報を含むトークンです。
  • アクセストークンは、リソースサーバ(ユーザー情報照会などをAPI化しているサーバ)を利用するためのトークンです。
  • リフレッシュトークンは、アクセストークンを再発行するためのトークンです。

認可コードとはトークンの引換券です。いきなりトークンを渡せない環境では一旦認可コードを渡し、認可コードを受け取ったアプリからトークンと交換します。

用途に応じたOAuthのグラント

oauth-story-flow4

スマホアプリやWEBアプリなど、環境に応じて安全なトークンの渡し方は違います。どのようにトークンを渡すのかによっていくつかのフローがあります。

スマホアプリ向けインプリシットグラント(Implicit Grant)

ユーザーに対して認可サーバが認証と同意を経た後で、アクセストークンを連携するフローです。

スマホアプリ向けのフローであり、スマホアプリのような秘密を確保できないへの情報連携向けです。ただ、特定のスマホアプリにうまくトークンを渡せないこと(後述、認可コード横取り攻撃)が判明し、多くの場合は社内向けのWebアプリのユーザー情報連携のために利用したり、ネイティブアプリケーションに対してあくまで識別子を渡すために使われます。

ただ、このフローについては使用されません。厳密アクセストークンを渡してしまうと仮に流出してしまった場合のリスクがでかすぎるからです。よって、ネイティブアプリやシングルページアプリケーションを利用する際には現実的に、認可コードとIDトークンを返すHybrid Grantを利用する方が望ましいといえます。本記事にはHybrid Grantの説明はありません。というよりも本体に仕様にもありません。Hybrid Grant自体、Implicit GrantとAuthorization Code Grantの認可コード、アクセストークン、IDトークンのマッピングから創出されたもので、仕様上での明確な定義がないのです。もっと言うと、こういうパターンでも利用できるよね、と世間的に勝手に作り出されたといってもいいでしょう。

レスポンス 認可コード アクセストークン (IDトークン)
認可エンドポイント
トークンエンドポイント

WEBアプリ向け認可コードグラント(Authorization Code Grant)

ユーザーに対して認可サーバが認証と同意を経た後で、認可コードを発行します。認可コードでアクセストークンを連携するフローです。

WEBアプリを動作させるWEBサーバは情報を秘蔵にすることができます。そのため、クライアントシークレットという事前に共有した秘密の値によりクライアントを特定することができます。

レスポンス 認可コード アクセストークン (IDトークン)
認可エンドポイント
トークンエンドポイント

レガシー向けリソースパスワードクレデンシャルグラント(Resource Password Credential Grant)

ユーザーに対してWEBアプリが認証と同意を経た後で、ユーザー自身が持つユーザーIDとパスワードからアクセストークンを発行するフローです。

アクセストークンを定期的にシステム自身が発行するためには、ユーザーIDとパスワードを適切に管理し続ける必要があります。しかし、外部システムがパスワードの暗号方法などをヒヤリングし、同等のポリシーで管理することは難しいでしょう。現実的には社内システムでの利用が中心となります。

レスポンス 認可コード アクセストークン (IDトークン)
認可エンドポイント
トークンエンドポイント

管理者向けクライアントクレデンシャルグラント(Client Credential Grant)

ユーザーの認証を挟まず、WEBアプリがアクセストークンを発行するフローです。

社内の管理者もしくは経済指標などの一般公開可能な情報向けに使われます。他のフローはユーザー認証と同意を経ることで、その同意に応じたAPIを提供します。そのため、そのアクセストークンで取得できるユーザー情報はユーザー自身の情報と同意した情報に限定されます。しかし、クライアントクレデンシャルでは、WEBアプリ自身がクライアントシークレットを発行し、ユーザー認証を行いません。

レスポンス 認可コード アクセストークン (IDトークン)
認可エンドポイント
トークンエンドポイント

再発行のためのリフレッシュトークン

oauth-story-refreshtoken2

リフレッシュトークンは、アクセストークンを再発行するためのトークンです。ユーザーがリフレッシュトークンをサービス提供者側に渡すことに同意するかにもよりますが、アクセストークンとセットで渡されます。アクセストークンの有効期限が切れた時、リフレッシュトークンでアクセストークンを再発行することにより、再度リソースサーバを利用できるようになります。

リフレッシュトークンなんて使わずに、アクセストークンの有効期限を長めにすれば?

いいえ、違います。セキュリティの抑止効果をもたらすことができます。アクセストークンだけだと、とりあえず当たるまで発行要求しつづけることを増長してしまいます。もちろん、複雑な文字列にするため当たらないのですが、そんなこと攻撃者は関係なく攻撃してきます。そこで、リフレッシュトークンという存在があれば、そのような攻撃事態を抑止できます。

ちなみに、リフレッシュトークンが必要な理由として、アクセストークンは使う頻度が多くて漏洩しやすいためというのは理由としては微妙です。同じ文字列を暗号化した場合、規則性から解読されるかもしれないという論理かもしれませんが、そんなレベルの暗号化通信であれば、そもそもユーザーのパスワードをあっさり解読されています。

リフレッシュトークンによるアクセストークン再発行

リソースサーバにクラウドAPIを使う

oauth-story-separated2

リソースサーバにクラウドAPIを利用するケースを紹介します。認可サーバはトークンを管理し、リソースサーバはユーザー情報を管理しAPIとして展開するサーバです。従って、リソースサーバでアクセストークンを受けた時、認可サーバに対してアクセストークンの検証が行われます。(上記のフロー図からは体裁のため削除しています。)

トークン検証

トークンによってAPI呼び出しを制御しているのは認可サーバになりますので、このリソースサーバは自社で管理している必要はありません。クラウドなどのAPIを利用することで幅広い構成が実現できます。

リソースサーバとしてクラウド利用

PKCE(Proof Key for Code Exchange by OAuth Public Clients)

PKCEは、認可コード横取り攻撃への対策として策定されました。認可コード横取り攻撃とは、認可レスポンスの認可コードを奪ってしまい、悪意のあるスマホアプリが正規アプリに成りすますことです。普通に考えれば奪われることはないように思えますが、スマホの環境ではブラウザで受けた認可レスポンスをスマホアプリに渡すとき、ブラウザからスマホアプリを呼び出します。その際、悪意のあるアプリに仕向けられると、ブラウザが受け取った認可レスポンスを悪意のあるアプリに渡してしまいます。

認可サーバから見ると、正しい認可コードであれば、認可リクエストを送ったスマホアプリなのか、悪意のあるスマホアプリなのか判別できません。

認可コード横取り攻撃

PKCEでは、正規のスマホアプリのみが発行できる値を作ります。スマホアプリで認可リクエストを発行する際に、code_verifierという値を付けることで、認可コードだけを奪われたとしても認可サーバは不正を検知できるわけです。

  • code_verifierとは、認可コードを検証するためのスマホアプリが発行する値です。
  • code_challengeとは、code_verifierの平文かハッシュ値です。どちらかは、code_challenge_methodで指定されます。
  • code_challenge_methodとは、code_verifierをどのように算出するか方法です。ハッシュ(S256)一択かと思います。
PKCE