「[[マイクロソフト系技術情報 Wiki>http://techinfoofmicrosofttech.osscons.jp/]]」は、「[[Open棟梁Project>https://github.com/OpenTouryoProject/]]」,「[[OSSコンソーシアム .NET開発基盤部会>https://www.osscons.jp/dotNetDevelopmentInfrastructure/]]」によって運営されています。 -戻る --[[OAuth 2.0 拡張]] --[[UserAgentでOAuth2のTokenを取得するベスト・プラクティス]] * 目次 [#p291d1f4] #contents *概要 [#jb3d7ad1] 認可コード横取り攻撃 (authorization code interception attack) への対策 -(Authorization Codeグラント種別により発行された)~ 認可コードをクライアントアプリケーションが受け取る際、~ 悪意のあるアプリケーションがその認可コードを横取りする攻撃に対抗する仕様。 -[[OpenID Connect]]の、[[Authorization Code Flow>OpenID Connect#mcde509a]]とも組み合わせることができる。 **課題 [#d588d1d4] ネイティブアプリが、外部ブラウザを使用してOAuth 2.0認証要求を発行する場合、 >「[[Implicit Flow>OAuth#m5c2d510]]ではなく、[[Authorization Code Flow>OAuth#yfeb403d]]を使用し、~ redirect_uriにPrivate-Use URI Schemeを使用してcodeを取得する。」~ という方式があるが(下図を参照)、 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+ | End Device (e.g., Smartphone) | | | | +-------------+ +----------+ | (6) Access Token +----------+ | |Legitimate | | Malicious|<--------------------| | | |OAuth 2.0 App| | App |-------------------->| | | +-------------+ +----------+ | (5) Authorization | | | | ^ ^ | Grant | | | | \ | | | | | | \ (4) | | | | | (1) | \ Authz| | | | | Authz| \ Code | | | Authz | | Request| \ | | | Server | | | \ | | | | | | \ | | | | | v \ | | | | | +----------------------------+ | | | | | | | (3) Authz Code | | | | Operating System/ |<--------------------| | | | Browser |-------------------->| | | | | | (2) Authz Request | | | +----------------------------+ | +----------+ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+ -Private-Use URI Schemeの上書き攻撃によって、このcodeが傍受されることがある。 -また、client_idや、client_secretも漏洩してしまう可能性がある。 **対策 [#j94e6ae3] -コード交換のための証明鍵(PKCE、 "pixy"と発音)を使用して脅威を軽減する。 -プロビジョニングされたアプリケーションのバイナリ・ファイル中のclient_secretについては、~ 機密性が考慮されていないため、client_secretを必要としない方式になっている。 *仕様 [#gb8fc333] **仕様の概要 [#obb75901] このフローは、 -Client ≒ デバイス(UserAgent)になる。 -redirect_uriにPrivate-Use URI Schemeが使用される点を除いて、~ [[Authorization Code Flow>OAuth#yfeb403d]]と同じだが、下記リクエストにパラメタが追加される。 --認証リクエスト --Tokenリクエスト +-------------------+ | Authz Server | +--------+ | +---------------+ | | |--(A)- Authorization Request ---->| | | | | + t(code_verifier), t_m | | Authorization | | | | | | Endpoint | | | |<-(B)---- Authorization Code -----| | | | | | +---------------+ | | Client | | | | | | +---------------+ | | |--(C)-- Access Token Request ---->| | | | | + code_verifier | | Token | | | | | | Endpoint | | | |<-(D)------ Access Token ---------| | | +--------+ | +---------------+ | +-------------------+ **仕様の詳細 [#sb35c097] -Clientは、認可リクエストを送信する前に、 --乱数 "code_verifier" を発生させ、 --[[ハッシュ関数>#k363fd25]] "t" を用いた --ハッシュ値 "t(code_verifier)"を計算する。 -Clientは、認可リクエストに以下のパラメタを含める。 --code_challenge_method:[[ハッシュ関数>#k363fd25]] "t" --code_challenge:ハッシュ値 "t(code_verifier)" -認可エンドポイントで、前述の認可リクエストを受信した際、これらを保存しておく。 -Clientは、Tokenリクエストに、先程生成した code_verifierパラメタを含める。 -Tokenエンドポイントでcode_verifierを含むTokenリクエストを受信した場合、保存されている --code_challenge_method:[[ハッシュ関数>#k363fd25]] "t" --code_challenge:ハッシュ値 "t(code_verifier)" >を使用して、code_verifierの妥当性を検証する。 -なお、このフローでは、client_secretは不要とする。 ***[[各エンドポイント>OAuth#h4dcb0c7]]で受け取るパラメタ [#rf81fec1] -認可エンドポイント |#|パラメタ|要否|説明|h |1|code_challenge|必須|Code Verifier を元に計算された Code Challenge の値| |2|code_challenge_method|任意|Code Challenge の計算に用いる[[ハッシュ関数>#k363fd25]]。&br;"plain"と"S256"があり、デフォルトは "plain"。| -Tokenエンドポイント |#|パラメタ|要否|説明|h |1|code_verifier|必須|動的に作成された暗号的にランダムな43-128文字のbase64url文字列| ***ハッシュ関数 [#k363fd25] -plain: --恒等関数(引数と同じ戻り値を返すの意) --code_verifierをそのまま使用する(ClientでS256がサポートできない場合)。 -S256: --BASE64URL-ENCODE(SHA256(ASCII(code_verifier))) --SHA-256 でハッシュ化した値を base64url に変換したもの。 ***codeとの関連 [#qe9e38a1] -サーバー・ステートレス~ 通常、"code_challenge"および"code_challenge_method"の~ 値は暗号化された形式で"code"自体に格納される。 -サーバー・ステートフル~ codeに関連付けられたAuthorization Serverに格納することもできるが、~ "code_challenge"と"code"を関連付ける方法は、仕様の対象外。 *セキュリティに関する考慮事項 [#id24a0d3] **code_verifier [#k379ad67] -code_verifierには充分なエントロピーが必要(256ビット以上)。 -生成には、適切なRNG(RNGCryptoServiceProviderなど)の使用が推奨される。 **盗聴者からの保護 [#r76df0b6] -通常、"S256"を使用する。~ PKCEをサポートするサーバーは"S256"をサポートする必要がある。 --"plain"では、"code_challenge" = "code_verifier"となり盗聴が可能。 --従って、通常、"plain"ではなく、"S256"を使用する必要がある。 -"plain"を使用する場合、 >サーバー・ステートレスで"code"から"code_challenge"および"code_challenge_method"を~ 取り出す場合の処理は、当該サーバだけが可能になるように実装する必要がある。 **code_challenge [#s821e3e8] code_challengeの生成にソルト(やストレッチ)が不要な理由。 -ソルトによって、辞書空間が大幅に拡張される。 -しかし、 --code_verifierはpasswordと異なり、エントロピーが高い。 --GPUの進化によってソルトの価値が減ってきている。 このため、code_challengeの生成にソルト(やストレッチ)は不要。 *補足 [#odafd559] **client_secret不要? [#k3b1f3c9] %%OAuth PKCE、client_secretは不要と言うが、%% -%%client_secret使わないで、アクセストークン・リクエストができたら安全ではない。%% -%%理由は、悪意の有るクライアントがclient_idダケ盗んで%%~ %%Private-Use URL Scheme 上書き攻撃で正規のOAuth PKCEフロー実行できるため。%% -%%なので、%% --%%Hybrid flow的に、codeとcode_verifierを、Client(フロントエンド)から%%~ %%Client(バックエンド)に渡してからアクセストークン・リクエストする必要がある。%% --%%なお、[[Financial API (FAPI)]]では、[[追加のクライアント認証>JWTとOAuth2.0#pebd83d3]]と組合せている。%% -OAuth PKCEのアクセストークン・リクエストでは、client_secretは不要で、client_idのみでOK。 --なので、client_secret_basic ではなく、client_secret_post っぽくポスト送付したりする。 --Auth0では、client_secret_post でもなく、client_secret_query 的だったらしい。 -SPAのベストプラクティスである~ 「Authorization Code Grant Flow with PKCE」では、~ Client(バックエンド)に渡してからアクセストークン・リクエストする。 -OSSコンソーシアム --PKCEのトークンリクエストはフロントエンドから?バックエンドから? ---①~ https://www.osscons.jp/jorfs4g6d-537 ---②~ https://www.osscons.jp/joxql6yjz-537 **オレオレPKCE [#t885d050] ***概要 [#fdf40453] -OAuth PKCEをサポートしていない Idp/Sts でClient側に実装を足して、~ PKCEッポくする処理シーケンス(本来は、リプレース予算の獲得するのが望ましい)。 -よりセキュアに、OAuth PKCEっぽく実装する場合、~ code_verifierをそのまま使用するのではなく、以下のcode_challengeとして送信する。~ なお、アルゴリズム(code_challenge_method)は、今の所、"plain"と"S256"のみ。 --code_challenge_method:ハッシュ関数 "t" --code_challenge:ハッシュ値 "t(code_verifier)" ***フロー [#y5663f4b] ① Resource Owner(ユーザ)がスマホ上のClient(スマホネイティブ・アプリ)をクリックする。 ② Client(スマホネイティブ・アプリ)が起動する。 ③ Client(スマホネイティブ・アプリ)のログイン ボタン or リンクをクリックする。 ④ 外部ブラウザが起動して、Client(バックエンドWebアプリ)へWebアクセスする。~ ☆ CSRF対策、カスタムURLスキーム上書き攻撃対策として、~ Client(スマホネイティブ・アプリ)は、固定でないstateに加えcode_verifierパラメタ付加しておく。~ ※ stateとcode_verifierパラメタは後で使用するので、Client(スマホネイティブ・アプリ)のローカル領域に保存しておく。 [ここからOAuth2のAuthoriaztion Codeフローでの認証] ⑤ Client(バックエンドWebアプリ)はClient(スマホネイティブ・アプリ)の要求を受けて~ Authorization Serverへリダイレクト(OAuth2のAuthoriaztion Codeを開始)する。~ ☆ CSRF対策として、Client(バックエンドWebアプリ)は、~ Client(スマホネイティブ・アプリ)から渡されたstateパラメタを付加する。 ⑥ Authorization Serverがログイン画面を表示する。 ⑦ Resource Owner(ユーザ)がクレデンシャル(ID, PWD)を入力する。 ⑧ Authorization ServerはAuthoriaztion Code(code)を発行し~ Client(バックエンドWebアプリ)のRedirectエンドポイントへリダイレクトする。 ⑨ Client(バックエンドWebアプリ)は、先ず、stateパラメタを検証し、stateが問題なければ、~ Authorization ServerのTokenエンドポイントへ AccessTokenリクエスト(codeを提示)する。 ⑩ Authorization ServerからClient(バックエンドWebアプリ)へAccessToken発行 ⑪ Client(バックエンドWebアプリ)は、AccessTokenを使用してUserInfoエンドポイントにリクエストし、~ ユーザー情報が取得できたらユーザがログイン(認証/認可)されたこととする。 [ここまでOAuth2のAuthoriaztion Codeフローでの認証] ⑫ Client(バックエンドWebアプリ)は、Client(スマホネイティブ・アプリ)用の一時codeを生成してcode_verifierと紐つけて保持する。 ⑬ 次に、カスタムURLスキームでClient(スマホネイティブ・アプリ)へリダイレクトし、これによって、一時codeとstateを渡す。 ⑭ Client(スマホネイティブ・アプリ)は、一時codeとstateを受け取り、先ず、state検証する。~ stateが問題なければ、一時codeと、④で指定したcode_verifierをClient(バックエンドWebアプリ)のTokenエンドポイントへポストする。 ⑮ Client(バックエンドWebアプリ)のTokenエンドポイントは、~ codeとcode_verifierを検証し、問題なければ認証tokenを発行する。 ⑯ Client(スマホネイティブ・アプリ)は、認証tokenを取得する。 ⑰ Client(スマホネイティブ・アプリ)は、 認証tokenを使用して~ Client(バックエンドWebアプリ)のWebAPIへアクセスし、~ 正常系のリターンがあれば、ユーザがログイン(認証/認可)されたこととする。 *参考 [#ca1689ad] -RFC7636として発行されたOAuth PKCEとは - r-weblife~ http://d.hatena.ne.jp/ritou/20151018/1445181974 -PKCE: 認可コード横取り攻撃対策のために~ OAuth サーバーとクライアントが実装すべきこと - Qiita~ https://qiita.com/TakahikoKawasaki/items/00f333c72ed96c4da659 -OAuth2.0で認可コードの漏洩を防ぐPKCE - 理系学生日記~ http://kiririmode.hatenablog.jp/entry/20170206/1486306800 --OAuth 2.0 and PKCE | Pedro Félix's shared memory~ https://blog.pedrofelix.org/2016/02/15/oauth-2-0-and-pkce/ -OAuth for Native Apps | GREE Engineers' Blog~ http://labs.gree.jp/blog/2015/12/14831/ --解決策1-2: OAuth PKCE 拡張を利用する **仕様 [#g417e99c] -RFC 7636 - Proof Key for Code Exchange by OAuth Public Clients~ https://tools.ietf.org/html/rfc7636 --OAuth 2.0 Threat Model and Security Considerations~ https://www.rfc-editor.org/rfc/rfc6819.txt --Recommendations for Secure Use of~ Transport Layer Security (TLS)~ and Datagram Transport Layer Security (DTLS)~ https://www.rfc-editor.org/rfc/rfc7525.txt **関連 [#xe006d83] ***[[OAuth PKCE利用時の構成図>UserAgentでOAuth2のTokenを取得するベスト・プラクティス#nd4ecb50]] [#l2a04fa7] ***[[OAuth 2.0 for Native Apps]] [#fd72f8ea] ***[[OAuth 2.0 for Browser-Based Apps]] [#m5706070] ---- Tags: [[:IT国際標準]], [[:認証基盤]], [[:クレームベース認証]], [[:OAuth]]