はじめに
世の中の OAuth & OpenID Connect の不適切実装の事例をリストしています。公式ドキュメントに「ドラフト段階の仕様をサポート」と断り書きが書いてあっても、最終仕様に違反している場合はリストしています。内容は適宜更新していきます。OAuth & OpenID Connect を実装する際の注意事項として参照していただければと思います。
仕様書を読むのは面倒だけど、OAuth & OpenID Connect をちゃんと実装しないといけない立場にある方は、是非 Authlete の使用を検討してください。(by Authlete 創業者)
事例
1. リダイレクト URI を正しく検証していない
John Bradley 氏の記事「Covert Redirect and its real impact on OAuth and OpenID Connect」を参照してください。
- Facebook (実装ぼろぼろ)
また、「OAuth 2.0 + OpenID Connect のフルスクラッチ実装者が知見を語る」の「リダイレクトURI」もご参照ください。
2. スコープ名の区切文字の間違い
認可エンドポイントやトークンエンドポイントに対するリクエストの scope
パラメーターは、スコープ名を複数列挙することができます。その際、区切り文字としてスペースを使うことになっています (RFC 6749, 3.3. Access Token Scope)。しかし、下記の OAuth 実装ではカンマを区切文字としています。
- GitHub
- Sportify
- Discus
- Todoist
3. アクセストークン有効期間秒数パラメーター名の間違い
認可サーバーは、アクセストークンを発行する際、その有効時間に関する情報を秒単位で返してもかまいません。その際、パラメーター名は expires_in
にすることになっています (RFC 6749, 5.1. Successful Response)。
- Facebook (
expires
というパラメーター名になっている)
4. トークンエンドポイントからの応答フォーマットの間違い
トークンエンドポイントからの応答は JSON です (RFC 6749, 5.1. Successful Response)。
- Facebook (
application/x-www-form-urlencoded
になっている) - Bitly (
application/x-www-form-urlencoded
になっている) - GitHub (デフォルトが
application/x-www-form-urlencoded
になっている)
5. トークンエンドポイントの応答に token_type が含まれていない
トークンエンドポイントからの成功応答には token_type
というパラメーターを含める必要があります (RFC 6749, 5.1. Successful Response)。
-
Salesforce (※1token_type
が含まれない。参考: OAuth Access Token Response Missing token_type) - Slack (
token_type
が含まれない)
[2016/05/15] ※1 本不具合は修正済みとの情報をいただきました。ありがとうございました。
6. トークンエンドポイントで grant_type が必須でない
トークンエンドポイントに対するリクエストでは、grant_type
パラメーターは必須です。しかし、下記の実装では grant_type
パラメーターを要求していません。
- GitHub
- Slack
- Todoist
7. エラー応答の error の値が不適切
- GitHub (
application_suspended
など、好き勝手にやっている) - Todoist (トークンエンドポイントに提示された認可コードが誤っていた場合、
error
がbad_authorization_code
となる。invalid_grant
であるべき。)
8. トークンエンドポイントへの client_secret パラメーターが必須
トークンエンドポイントにクライアントシークレットを渡さなければならないのは、クライアントアプリケーションのクライアントタイプが confidential であるか、もしくは、クライアントタイプが confidential でなくともクライアントシークレットを発行されている場合のみです。仕様上は、認可サーバーは public クライアントに対してもクライアント認証を求めてもよいことになっていますが、「クライアントシークレットを保っておくことができないクライアントを public クライアントと呼ぶ」との定義を踏まえると、トークエンドポイントへのリクエストで必ずクライアントシークレットを求めることは、間違いとは言えないものの、不適切です。 (RFC 6749, 2.3. Client Authentication)
- Todoist (
client_secret
パラメーターが必須となっている)
9. アクセストークンを取り消せない
実装間違いとは言えませんが、アクセストークンの意図を考えると、アクセストークンを取り消せないというのは不適切な実装です。
- 某世界的な SIer のパッケージ
10. アクセストークン大量累積
アクセストークンの消し込み処理を考えずに実装すると、使われていないが消すに消せないアクセストークンが大量に累積することになります。
- 某国内大手サービスの実装
11. PKCE 非サポート
これを不適切実装というのは酷ではありますが、もしもスマートフォンアプリ等の public クライアントに対して認可コードフローでアクセストークンを発行するのであれば、認可コード横取り攻撃に対する対抗策である RFC 7636 (Proof Key for Code Exchange by OAuth Public Clients; PKCE) のサポートは、必須と言ってよいでしょう。実際、(ドラフト段階ではありますが) 「[OAuth 2.0 for Native Apps](OAuth 2.0 for Native Apps)」という文書には次のように書いてあり、
Both the client and the Authorization Server MUST support PKCE [RFC7636] to use custom URI schemes, or localhost redirects.
認可コードを受け取る際に、カスタムスキームや localhost へのリダイレクトを用いるのであれば、PKCE のサポートは必須とされています。
英文ですが、PKCE の図解はこちらにあります。
12. token_type 不整合
アクセストークン発行時に token type の値として Bearer を返しているにも関わらず、リソースエンドポイント群が RFC 6750 (The OAuth 2.0 Authorization Framework: Bearer Token Usage) で定義された方法でアクセストークンを受け取らないという実装があります。
- GitHub (
Authorization: token OAUTH-TOKEN
というフォーマットでアクセストークンを受け取る)
13. エラーコードのパラメーター名が error ではない
- LINE (認可リクエストでエラーが発生すると、
error
ではなくerrorCode
というパラメーターでエラーコードを通知する)