MS_OAuthExternalLoginResearch - NetDevInfraWGinOSSConsortium/NetDevInfraWiki GitHub Wiki

OAuthによる外部ログイン(認証)の研究

概要

  • 外部ログイン(認証)の仕様の調査。
  • 前提知識に、OAuth 2.0 の知識を要する。

外部ログイン(認証)の仕様

外部ログインは、OAuth 2.0「Authorization Code グラント種別」の拡張仕様になる。

  • 通常、OAuth 2.0では、Redirect エンドポイントには、仲介コードが返り、
    仲介コードをサーバ側で Access Token に変換した後、Resources Server へアクセスし、
    必要な Resources(ここでは認証されたユーザのクレーム)を取り出して返すと言う流れになる。

  • しかし、外部ログインでは、Redirect エンドポイントに直接、このクレームが返る
    (外部ログイン・ライブラリ上で、仲介コード → Access Token → クレームへの変換処理をしている)。

補足(「直接返る」ように見える理由): 正確には、
ライブラリが Redirect エンドポイントの内部で
仲介コード → Access Token → クレームまで一気に処理している
ため、
アプリケーション側のコールバックから見ると
「クレームが直接返ってきた」ように見える、という意味である。
プロトコル上の往復が省略されているわけではない。

ASP.NET Identity用のMicrosoftアカウントの外部ログイン・ライブラリの場合

動作を分析した所、

  • 実際の Redirect エンドポイントは、
    http://localhost:nnnnn/signin-microsoft

  • アプリケーションの Callback のエンドポイントが、
    /Account/ExternalLoginCallback

となっている。

HTTPS のため、仲介コード → Access Token の、Response を確認できず、
OpenID Connectで実装されてる可能性もあると考えたが、
scope パラメタに「openid」の値を確認できなかったので、
OAuth 2.0 拡張と思われる。

補足(現在は OpenID Connect): 本調査の当時(ASP.NET Identity +
Microsoft.Owin.Security.MicrosoftAccount)は、Microsoft アカウントの
外部ログインが OAuth 2.0 ベースで実装されていた。
現在の ASP.NET Core(Microsoft.AspNetCore.Authentication.MicrosoftAccount
および Microsoft Entra ID 向けの Microsoft.Identity.Web)は
OpenID Connect ベースで、scopeopenid を含み、
ID トークンを受け取って検証する。
openid が無いので OAuth 2.0 拡張と思われる」という本文の推論は、
当時の実装については妥当である。

Redirectエンドポイント

仲介コード → Access Token → クレームへの変換処理を行っている模様。

  • GET http://localhost:nnnnn/signin-microsoft?code=AAAAA&state=BBBBB HTTP/1.1

  • Cookie:

    • ASP.NET_SessionId=XXXXX
    • __RequestVerificationToken=YYYYY
    • .AspNet.Correlation.Microsoft=ZZZZZ1

Callbackのエンドポイント

この時点で情報は全て、.AspNet.ExternalCookie に同梱されるもよう。
(恐らく、クレームなどの情報の露見を防ぐためと思われる)

  • GET http://localhost:nnnnn/Account/ExternalLoginCallback HTTP/1.1

  • Cookie:

    • ASP.NET_SessionId=XXXXX
    • __RequestVerificationToken=YYYYY
    • .AspNet.ExternalCookie=ZZZZZ2

遷移元への遷移

認証後、遷移元へ遷移した後には、外部ログインの形跡は綺麗に消えている。

  • GET http://localhost:nnnnn/ HTTP/1.1

  • Cookie:

    • ASP.NET_SessionId=XXXXX
    • __RequestVerificationToken=YYYYY
    • .AspNet.TwoFactorRememberBrowser=ZZZZZ3
    • .AspNet.ApplicationCookie=ZZZZZ4

補足(Cookie の役割): 上記 3 段で現れる Cookie は、それぞれ役割が異なる。

Cookie 役割 寿命
.AspNet.Correlation.<Provider> state の検証用(CSRF 対策) 認可リクエスト〜Redirect の間
.AspNet.ExternalCookie 外部 IdP から得たクレームの一時受け渡し Callback 〜 サインインの間
.AspNet.ApplicationCookie 自アプリのサインイン状態 セッション/永続

「遷移後、直ちに削除している」のは上 2 つで、
最終的に残るのは自アプリの .AspNet.ApplicationCookie だけになる。

セキュリティに関する考慮点

以下をライブラリ内で処理することで、セキュリティを高くしている。

  • 外部ログインを、ライブラリ内部で処理して、

    • ユーザの実装ミスによる仲介コード、Access Token 等の露見を防いでいる。
    • 長目の RequestVerificationToken 値を使用している。
  • Redirect エンドポイント→ Callback のエンドポイント間で、

    • 仲介コード、Access Token 等が露見しないよう、エンドポイントを 2 段構成にしている。
    • エンドポイント間のインターフェイスに Cookie(ExternalCookie) を使用し、遷移後、直ちに削除している。

補足(2 段構成の意味): signin-microsoft
ライブラリ専用の受け口にしてアプリのコードを一切通さないことで、
仲介コードや Access Token がアプリ側のログ・リファラ・例外画面に
漏れる経路を断っている。
これは OAuth 2.0 Security Best Current Practice
「HTTP リファラからの code 漏洩」への対策と同じ発想である。

参考


Tags: IT国際標準, 認証基盤, ASP.NET Identity, OAuth

⚠️ **GitHub.com Fallback** ⚠️