こんにちは!バクラク事業部の@ysakura_です。普段はバクラクビジネスカードの開発をしています。
先日、Partner APIの開発を担当する事になり、その前段としてバクラクシリーズ全体で利用できる OAuth 2.0 の認可サーバーを開発しました。
OAuth 2.0 により、Partner APIのセキュリティ向上を目的としています。
今回は入門記事として、 OAuth 2.0 の元となる課題感 / OAuth 2.0 での解決方法 / API Key方式との比較 を画像を交えながら説明します。OAuth 2.0 は分かった様で分からない状態になる事も多いと思うので、理解の一助になれば幸いです。
※ あくまで入門記事ですので、OAuth 2.0 の詳細なフロー図などは出てきません。
前提となるシナリオ
他社のシステム(SaaS等)にデータを連携するシーンを考えます。
例として、バクラクビジネスカード
から架空のサービスA
にカードの明細情報を提供するとします。
例えば、会計ソフトへの連携などが該当します。
OAuth 2.0 の元となる課題感
システム間で実際にデータ連携をするには、どのユーザーの情報が必要かを伝えて貰う必要があります。
この状況において、OAuth 2.0 のRFCに挙げられている問題点のある方法をまずは紹介します。
参考: https://openid-foundation-japan.github.io/rfc6749.ja.html#anchor1
バクラクの ID / Password を渡す
よくある方法として、ユーザーにバクラクの ID / Password を入力して貰う方法があります。
その入力して貰ったパスワードをバクラクに直接渡す事で、どのユーザーの情報が欲しいかを明示できます。
この方式の問題点
この方式にはいくつかの問題点があります。
パスワードの漏洩リスクがあること
バクラク以外のサービスにパスワードを登録するので、作業中にパスワードを盗まれるリスクがあります。例えば、コピペの為に一旦メモに書き写すなどです。また連携元のサービスでの管理が悪いと、連携元サービスからのパスワード漏洩リスクもあります。
ログインが出来るので、ユーザーの情報を引き抜いたり、ユーザーになりすます事が可能です。
パスワードがハッシュ化されずに保持されること
パスワードは平文や暗号文ではなくハッシュ値として保存する事が一般的かと思います。ただ、この方式ではユーザーの代わりにログインを行う必要があるので、ハッシュ化されずに平文や暗号文で保持されてしまいます。
その為、パスワードの漏洩リスクが比較的高まります。
※ ハッシュ化したパスワードを使うIFにする等の対策も可能ですが、意識していないと危険なままです。
パスワード漏洩が起こると、全ての連携で再連携が必要なこと
この方式では、全てのサービス間連携で同じ ID / Password を入力する事になります。
その為、どこかのサービスでパスワード漏洩が起こると、パスワードを変更してから連携するサービス全てで再連携が必要になります。
特定の連携を解除するには、パスワード変更が必要なこと
上述の通り、全てのサービス間連携で同じ ID / Password を入力します。
その為、特定の連携を解除しようとすると、パスワードを変更してからそのサービスでは再連携を行わない、という事が必要になります。
※ 連携元のサービス側で連携解除の機能があればこの対応は不要です。
連携の有効期限やアクセス権限を設定しづらい
バクラクの ID / Password を入力して貰う形なので、連携の有効期限やアクセス権限の機能を作るには自前で対応が必要です。
その為、意識していないと攻撃が行いやすい作りになってしまう事があります。
※ ユーザー自体の権限などで制御は出来ますが、3rd Party Onlyのロジックは追加実装が必要になります。
OAuth 2.0 での解決方法
上記の問題は大きく分類すると、下記の4つに分かれます。
- 連携用のクレデンシャルを安全に受け渡し出来ない
- パスワードの漏洩リスクがあること
- ユーザーが入力をする必要がある為
- パスワードがハッシュ化されずに保持されること
- パスワードの漏洩リスクがあること
- 連携元毎のクレデンシャル管理が出来ない
- パスワード漏洩が起こると、全ての連携で再連携が必要なこと
- 特定の連携を解除するには、パスワード変更が必要なこと
- 有効期限の設定が難しい
- アクセス権限の設定が難しい
以下では、よく使われる認可コードフローにおいて、OAuth 2.0 がこれらの問題をどう解決しているか解説します。
※ Confidential Client の場合の説明です。
連携用のクレデンシャルの安全な受け渡し
どの様に安全に受け渡しされるかを見る為に、処理の流れの解説からします。
OAuth 2.0 の認可コードフローの大まかなフロー図と特徴は下記の通りです。
フローの概要
番号昇順で連携の流れを表しています。
特徴
特に重要な点に下線を引いています。記載のとおり、安全にクレデンシャルを受け渡しする事が出来ます。
- 認可コードと呼ばれる使い捨てのコードがバクラクから発行される(4.)
- OTP(ワンタイムパスワード)の様なものです。
- 連携用のクレデンシャル発行は、連携元からバクラクを直接呼び出す形で実行される(5.)
- 認可コードを使う事で、連携するユーザーが誰かを判別する
- ブラウザを介さず、バックチャンネル(サーバー間)に通信が閉じる
- 結果として、ユーザーが連携元サービスにバクラクの認証情報(ID/Password)を渡す事が無い
- クレデンシャルの発行には、Client認証が必要で誰でも使える様にはなっていない(5.)
補足
OAuth 2.0 は認可のフレームワークであり、認可サーバーという認可のレイヤーを設ける事で連携専用のクレデンシャルを発行します。
認証と認可の違いについては、クラスメソッドさんの記事が分かりやすいです。
https://dev.classmethod.jp/articles/authentication-and-authorization/
連携元毎のクレデンシャル管理
連携毎に新規でクレデンシャルが発行されるので、(ユーザー × 連携元) の粒度でクレデンシャルを発行する事が出来ます。
※ このクレデンシャルを アクセストークン
と呼びます
有効期限
OAuth 2.0 ではアクセストークン(クレデンシャル)に有効期限が設定されます。
リフレッシュトークン
という専用のトークンを用いる事で、アクセストークンの有効期限も延長する事が出来ます。
権限
OAuth 2.0 では Scope
を用いて、アクセスする範囲を明示します。Scopeは連携元のClientから指定され、そのScopeに基づいたアクセス要求が同意画面で表示されます。
下記はバクラクシリーズでの同意画面の例です。
API Key方式との比較
ここまで ID / Password 方式 と OAuth 2.0 を比較してきました。
ID / Password 以外のAPIの認証方法としてよく挙げられるのがAPI Key方式です。
OAuth 2.0 のこれまでの解説を踏まえて、API Key方式との比較を行います。
API Key方式とは
API Keyと呼ばれる連携専用のクレデンシャルをバクラクに発行して貰う形式です。
API Keyはログイン用の ID / Password と異なり、API Keyを用いてログインは出来ないのでセキュリティが向上します。
API Key方式で ID / Password の問題点を解決出来るか
結論から言うと可能だと考えています。
API Keyの安全な受け渡し
API Keyをユーザーがコピペする必要があるので、その段階における漏洩リスクは残ります。ただ、ログイン用の ID / Password ではないので漏洩時のリスクは比較的軽減します。
後述の通り、有効期限や権限やの機能を開発しておけば、サービス提供者としては許容できるリスクになりうると思います。
またAPI Keyの削除機能を提供する事で、仮に漏洩したとしてもそのAPI Keyを無効化する事も可能です。
連携元毎のクレデンシャル管理
API Keyを連携元毎に発行すれば可能です。ユーザーがAPI Keyの入力を仲介するので、ユーザー側の管理・運用のコストは上がります。
有効期限の設定
有効期限のあるAPI Keyを開発すれば可能です。通常のログイン方式とは分離されているので、比較的行いやすいです
アクセス権限の設定
権限が紐づくAPI Keyを開発すれば可能です。同様に通常のログイン方式とは分離されているので、比較的行いやすいです
OAuth 2.0 が勝る点
API Key方式の紹介をしたので、OAuth 2.0 との比較をしてみます。
下記の観点では OAuth 2.0 に軍配が上がると思います。
機能的にはどちらも ID / Password 方式の問題点をクリア出来るため、開発観点での比較が主です。
API Keyでは属人性や負債化のリスクが高い
API Key方式でもセキュアな連携は可能ですが、セキュアにするには自前で権限や有効期限などの設計をする必要があります。しかし、設計に気をつけないと所謂オレオレ実装となり属人性が上がったり負債化してしまうケースがある様に思います。
一方で、OAuth 2.0 は様々なRFCを通じて、インターフェース面の取り決めがあります。これを0ベースで実装する事は大変ですが、認可サーバーのライブラリやSaaSが昨今は揃っているので、比較的楽に実装する事が可能です。
世の中で OAuth 2.0 が広く使われていること
API連携の文脈では、連携を行うClient側が OAuth 2.0 に慣れている事も多く、信頼された共通プロトコルとして OAuth 2.0 が採用される事が多い様に思います。
こういった共通言語がある事は、他社と連携を行う際には便利です。OAuth 2.0 や 特定のRFCに準拠する形で、自前で実装したりライブラリを使えばよい話になります。
コミュニティの恩恵を受ける事が出来る
OAuth 2.0 や OpenID Connect の分野ではコミュニティの活動が盛んです。
OSSやRFCが日々発展しており、その恩恵を受ける事が出来ます。
また、日本語でも記事が多く書かれているのはメリットの1つだと思います。
OSS
例えば、OAuth 2.0 関連のライブラリでは 下記が有名かと思います。
- https://github.com/ory/hydra(CLI)
- https://github.com/ory/fosite(Go言語)
- https://github.com/doorkeeper-gem/doorkeeper(Ruby on Rails)
RFC
RFCもセキュリティやネイティブアプリなど様々な観点で追加されています。
- セキュリティ面のベストプラクティス
- ネイティブアプリ
API Key が 勝る点
API Key方式にもメリットがあると考えています。
キャッチアップコストが低く開発スピードが速い
API Keyを最低限実装する場合はKey生成のロジックを作ればよいので、権限や有効期限の機能を作るにしても実装量は少ないです。
OAuth 2.0 の認可サーバーを作るには OAuth 2.0 の理解を深める必要があるので、初期のキャッチアップコストがかかります。ライブラリやSaaSを使う場合でも、ある程度の知識は必要になってきます。
その為、開発スピードを優先する場合はAPI Keyに軍配が上がるシーンは多いと思います。
比較パートの結論
上記を元に私の考えを纏めると、セキュリティを初期から担保するなら、OAuth 2.0 を使いライブラリや日々発展するコミュニティの恩恵を受けるのが良いのではないかと思います。
一方で、開発スピードが重要である場合は API Keyを提供するのも1つの手かと思います。API Key方式を version.1
のAPIとして提供し、後から OAuth 2.0 対応をして version.2
とするのも1つの手だと思います。
この記事のまとめ
OAuth 2.0 を使う事で安全にサービス間の連携を行う事が出来ます!
Further Reading
興味を持った人向けの学習コンテンツ