OAuthと認証と認可とOpenIDConnect

OAuthについて他人に説明する機会があったので、まとめてみました。

# 認証（Authentication）
認証は誰であるかを確認することです。

例えば、パスワード認証。
その人しかしらないパスワードがわかるならそれは本人です。

例えば、指紋認証。
生体的特徴が一致するならそれは本人です。

# 認可（Authorization）
認可とは権限をあたえることです。

認証と認可はセットになっていることが多いです。
ATMからお金をおろすにはキャッシュカードとパスワードが必要です。
キャッシュカードで口座を特定し、パスワードでキャッシュカードの持ち主本人かを認証し、口座からお金をおろす許可を与えています。

認証のない認可の例としては、電車の切符があります。
切符を持っていれば電車に乗る許可が与えられますが、切符を持っている人が誰かを確認したりはしません。

# APIへの認可
たとえば、クライアントアプリ用のAPIを作ったとします。
![](http://www.plantuml.com/plantuml/png/SoWkIImgAStDuNhSjEXny_J7pQiKTEqK70Cy5QmK7ZUtFsxUyxXf_xFPMvvDs_2uSVhZncLSG3cG4hXwe48a-VcFcpgu75BpKe1c0W00)

でも、APIを無制限に公開すると悪い人がアプリ以外からAPIを実行してしまいます。
![](
http://www.plantuml.com/plantuml/png/SoWkIImgAStDuKfCBialKdZMjEfnOykJNRku7ZSjUjmy_N7pAWLTEmN704y5AuN7pUsFc_SyRjh_RFQMPzCsF6wS_hXn6HTG3gG4hXwe44b-_kEc3YwugGgwqSf9EQMfiOIDHAX4wCOqsI4rBmNeUW00)

なので、アプリ内に秘密の鍵を持たせて、鍵が一致しないアクセスを弾くことにします。
アプリは認可されており、悪い人は認可されていない状態です。
![](http://www.plantuml.com/plantuml/png/SoWkIImgAStDuKfCBialKdZMjEfnOykJNRku7ZSjUjmy_N7pAWLTEmN704y5AuN7pUsFc_SyRjh_RFQMPzCsF6wS_hXnsViz7TelUxU-tzF91LG5LEol0DSAr8EaTFxZfWukk0KAkhhHoaavfQcnU8q76ufG6e5m8L07qDx7ZJsF6q4YZnkx7pTrFcvSyBYf4KnsS3cavgK0lGO0)

次にこのAPIでユーザー毎のデータを管理することを考えます。
このアプリの利用者にみんなに同じ鍵を付与したままだと、違うユーザのデータでも更新したり閲覧したりできてしまいます。
![](http://www.plantuml.com/plantuml/png/SoWkIImgAStDuKfCBialKdZSlEnnyvx7JTiCqGMCkBWGaWgwTWgE0PuALaWQ7ZUkUzpS3kRiVpPxoxDf6nutJd_SkEpzdWxjbxrRt-_fv09fqGLgHMYoKa1IElznKmUIBKPOR34YnnOZ1LAjCQIMDGwfUId0q0K0)

そこで、同じアプリでもユーザ毎に違う鍵を付与することにしましょう。
各ユーザは自分のデータのみについて更新権限が付与されました。
![](http://www.plantuml.com/plantuml/png/SoWkIImgAStDuKfCBialKdZSlEnnyvx7JTiCqGMCkBWGaWgwTWgE0PuALaWQ7ZUkUzpS3kRiVpPxoxDf6nutJd_SkEpzdWxjbxrRt-zP-7vF9nT8bovGDqAVbGAIwlcFcpgGB3B2Of4HGOiMeLY4C8jKcmn9iYa2oIg2finytDGDTaCZK1PerEF6dfUDKnytje5SvP2QbmAC4W00)

# OAuth
OAuthは上の図の認可の仕組みを標準化したものです。
認可を与えるためのAuthサーバが登場し、鍵の代わりにアクセストークンを付与します。

OAuthには色々な方式の認証フローがありますが、以下はImplicitフローと呼ばれる簡易な方式です。
![](http://www.plantuml.com/plantuml/png/VPBDIiDG48NtzobcgKXV893IBjtv2aK55_v0JVVEtAej4PI2b6vCuw9QnGOHnP_WonmQtVKLpBr2J48ZX6pcv3iVCsaSUgssrzdRLQrDxw1Dq1Fe6FAYbEiIv1eIGJuWRz0zEucWdy2phz7xTtX6hgjCI0-XxwXMfsR7su4ycwI-8EUFb-ZZ-VWHV5zWyWZYWmC8fypcndhwpWUIsodu73m6NuAxgeYlfOLPWKEPY6afGmGy04yWadBiSsFQsLSPmV8A3GuLmjBxJu2Swdt982-Nl8RWeR79jFWXxr6dB4vEKGdiG_hLHMAcnlZJLWGu4dlAtztEPy6IgvdXibk5a5FmYLr_TsMjgdHLcUzh9MjmP3scbd2rY7ib_YBkgyRs_bRwy_q0)

## OAuthによる認証
OAuthは認可のための仕組みでしたが、それを認証にも使っちゃおうという考えです。
GoogleでログインとかFacebookでログインとかよくあるあれです。
![](http://www.plantuml.com/plantuml/png/VPFDYXf158NtzHIrJ0Y-G4EBBjtv0Db84iWYCM3QVUujumyQ5CM8cwX9C9gW9eI4-H5Vvj0wErzXgagPiiRfWQPfgCjtlbk7phoF2gMe_FQDABo8tfKar1Hg3VwV5I8C9VWhU0M-1bz2rUtH2kelQBaRNjrCMZ8CXHbI0wYVCfMMsNBq6lpFJAgE31nmgpx6up-WNnwJXk0cQ0GcpSpcS_fzEh2TpK5jq1ZK1rM4Zq_fG6SSo3iJ5-Ce3Eg2fc3M8FlyCF7K50vXYLv68BrfhZ-g88FaA-FkgTxsOW8QQ1ydHWlF9EtMqLWlLKk36yb9R4wDyyPcZF213tMg1VWt-BkUYclJNQTwtby-PvQWdYd2R_oioWcu1ghQTYfFdYNvF1K6chgt46Xb5UUMy6M_hhlbTTWXOxzkU7e-uRZdDxrXKlRXffuN7s23Md7xSxmPs6e_6GWjzRS_t0VtGBDZLoVt9pAlYY_rZtCB)


## OAuthを認証につかう危険性[^1]
[単なる OAUTH 2.0 を認証に使うと、車が通れるほどのどでかいセキュリティー・ホールができる](https://www.sakimura.org/2012/02/1487/)

アプリAが悪意を持っていた場合、アプリAがユーザAにもらったトークンでアプリBにログインし、
アプリB内のユーザAの情報を閲覧・更新できてしまいます。
![](http://www.plantuml.com/plantuml/png/hPJ1QXDH58Rtzoa6t2YI5nWSQRjpvzwwYBLWeOwbJlQUSwkcD1A9hKCGR4UbjfKaYYXgObxc9pUwoYjuvYPuvyPCLa88mprdlly__ptCoiEakflKxc-hwaRoO3U0FeKUWB-kgXqfR6rixLJZ902_WKwXBqgErxpZrLfo3_mb1-ddVkNc3QMYoBx8FN0V_1swRYLxq9z1tN7xnw-i4KIHSg91vReF3KBdrEZ7evDFe0yUbDhW0z0nc0Ggkl9VR31dvw0cw0Hq1DfJFhuYWYwAi32_qt4O1hL0fs0Malszp_NfG3c6HNeYOU1rStsfXo0i3urRdZ_pBGEbOiWveuvdHS0ksz2t9RR1--LQB5NhUcX5Zl68xPKMkyO_kwRvoXpsJKlFt-IjItUsQvkt2nRM_eE5zNWogBiHGTqbQTc0sfF1ld8UdB5yIVEqwKLEyPVpdwNBm4z1J-mUxLs-MYPwHGdqhqHbRdXGpuvpRaclvoUPQfNQzL6pSDvABAK9s7ZNumKYeCQe-N8qJErIFXE8bEJPRpu2IpPdioNJ7V17y3iX5o_wMkcqZhI8CJqnV97hK6eEXx-pXbhPZE_AL-eF)

なぜ、こんなことが起きるかといえばOAuthが認可の仕組みだからです。
アクセストークンには認証機能がありませんから持ち主が誰かは気にしません。

アプリBがOAuthをログインに使ってさえいなければ、
アプリAはユーザAにもともと許可された範囲の情報にしかアクセスできず問題はなかったのです。

# OpenID Connect
OpenID ConnectはOAuth2.0の仕組みに認証の機能を追加したものです。
OpenID Connectではアクセストークンと一緒にIDトークンを返却します。

IDトークンには認証に必要な様々な情報が含まれており、IDトークンを検証することでOAuthで問題となっていた脆弱性の多くを解決することができます。

IDトークンの検証例 ＞ [Yahoo! ID連携　IDトークンの検証](https://developer.yahoo.co.jp/yconnect/v2/id_token.html)
例えば、先程のOAuthでの問題は、以下の検証で検知できます。
> 対象のウェブサイトやアプリケーションと異なるサービスに発行されたID Tokenでないことを確認するために、Payloadのaud値に対象のウェブサイトやアプリケーションに発行されたClient IDの値が含まれていることを検証します。

# その他
リフレッシュトークンとか、クライアントシークレットの問題点などについても追記したい。


[^1]: [図解：OAuth 2.0に潜む「5つの脆弱性」と解決法](https://www.atmarkit.co.jp/ait/articles/1710/24/news011.html)