「[[マイクロソフト系技術情報 Wiki>http://techinfoofmicrosofttech.osscons.jp/]]」は、「[[Open棟梁Project>https://github.com/OpenTouryoProject/]]」,「[[OSSコンソーシアム .NET開発基盤部会>https://www.osscons.jp/dotNetDevelopmentInfrastructure/]]」によって運営されています。

-[[戻る>UserAgentでOAuth2のTokenを取得するベスト・プラクティス]]
-戻る
--[[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]
OAuth PKCE、client_secretは不要と言うが、

-client_secret使わないで、アクセストークン・リクエストができたら安全ではない。
**client_secret不要?問題 [#k3b1f3c9]

-理由は、悪意の有るクライアントがclient_idダケ盗んで~
Private-Use URL Scheme 上書き攻撃で正規のOAuth PKCEフロー実行できるため。
***概要 [#q94b6549]
OAuth PKCEのアクセストークン・リクエストでは、client_secretは不要で、client_idのみでOK。
-なので、client_secret_basic ではなく、client_secret_post っぽくポスト送付したりする。
-Auth0では、client_secret_post でもなく、client_secret_query 的だったらしい。

-なので、
***参考 [#s63ff1ec]
-OSSコンソーシアム
--PKCEのトークンリクエストはフロントエンドから?バックエンドから?
---①~
https://www.osscons.jp/jorfs4g6d-537
---②~
https://www.osscons.jp/joxql6yjz-537

--Hybrid flow的に、codeとcode_verifierを、Client(フロントエンド)から~
Client(バックエンド)に渡してからアクセストークン・リクエストする必要がある。
**オレオレPKCE [#t885d050]

--なお、[[Financial API (FAPI)]]では、[[追加のクライアント認証>JWTとOAuth2.0#pebd83d3]]と組合せている。
***概要 [#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へアクセスし、~
 正常系のリターンがあれば、ユーザがログイン(認証/認可)されたこととする。

**スマホ向けPKCE [#i133571b]
***[[Authorization Code Grant Flow with PKCE]] [#f3cfb634]
[[SPA>Single-page application]]でPKCEする場合のプロファイル。

*参考 [#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]]


トップ   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS