ちりもつもればミルキーウェイ

好奇心に可処分時間が奪われる

google sign inでiOS/Androidのclient SDKを使うとnonce指定できなくねという話

はじめに

タイトルまんまなんですが困っています。世界の人たちどうしてんの

こんばんはconvtoです。故あってgoogle sign inの仕様について調べてたんですが、表題通りの問題を見つけて頭を抱えています。
お客様の中に医師免許を持った有識者の方いらっしゃいましたら助けてください。

google sign inまわり、古いドキュメントも新しいドキュメントもいっぱいあって全体像があんまりつかめてないので僕が混乱してるだけかもだけど、だとしたらそれはそれで嬉しいのでとりあえず投下しておく

[追記]
インターネットから知見があつまりAndroidは大丈夫な雰囲気あります!記事の末尾に追記してます
iOSはまだnonce渡す手段見つかってないので引き続き調査中 & 有識者の意見お待ちしております

なにが問題なの

OIDCぽいのにnonceが指定できないから、session管理者がnonceの検証できなくてリプレイ攻撃の可能性がある

どゆこと

いわゆる「ほげほげでログイン」的なやつはたいていclient用のSDKが提供されがちですが、google sign inも例にもれずiOS/Android/JavaScriptのclientライブラリを提供してます。
(おまけにserversideのclient向けにもいくつかの言語で提供されてる)
丁寧にそれぞれのプラットフォーム向けの導入ドキュメントもある

で、なにが問題かっていうと、client SDKの作り的にnonce指定できないんすよねぇ。
clientとしてはnonceの検証はかなりやりたいんすよな

openid.net

String value used to associate a Client session with an ID Token, and to mitigate replay attacks. The value is passed through unmodified from the Authentication Request to the ID Token. If present in the ID Token, Clients MUST verify that the nonce Claim Value is equal to the value of the nonce parameter sent in the Authentication Request. If present in the Authentication Request, Authorization Servers MUST include a nonce Claim in the ID Token with the Claim Value being the nonce value sent in the Authentication Request. Authorization Servers SHOULD perform no other processing on nonce values used. The nonce value is a case-sensitive string.

一応そう判断したソースを貼っておくと

iOS/AndroidともにSDKではnonce指定不可、iOSは内部でnonce検証してるけどsession管理をserverでやるケースに置いては意味無し!という理解です。

ようはsession管理者をserverside側としたとき、iOS/Androidのclient SDKをつかうとsession管理者がnonceを知ることができないためsessionに紐づくnonceとID Tokenのnonce claimを突合できんわけです。

そもそもnonceは、sessionに紐付いたnonceを採番してわたすことでsession管理者がID Tokenのnonce claimと突合できて同一sessionで作られたID Tokenかわかる!からリプレイ攻撃されてもすでに正規loginでnonceが使われててもうないで〜とかいえるんでログイン弾けるやーつでして、まあそれがないと渡されたID Tokenをすべて全面的に一連の認証フローを経て正式に発行されたものと信頼するしかほかなくリプレイ攻撃のおもちゃになります。

なぜiOS/Androidのclient SDKで渡せないのか意味不明

iOS/Android SDKはclient以外にID Token渡すことを想定してないのかな?

そうか、そもそもclient以外にID Tokenを渡す想定してないんだな?発行したclientでのみの利用を想定してるなら、ついさっき自分で発行したばっかりだから信頼できそう?とおもったそこのあなた! 残念でした、serverとかにID Token渡してsession開始する使い方も想定してるようです

ご丁寧にID Tokenをserverにおくってserverのsessionを開始させてloginさせよう!という趣旨のドキュメントがあり、むしろそういう用途が主に想定されてるようです。ひょえ〜

つまり?

読み取った内容が正しければ、iOS/Androidのclient SDKを使うとsession管理者が管理するnonceを利用することができないため、リプレイ攻撃に対してなすすべがない。となります

有識者の意見を求めています

冒頭の通りお客様の中に医師免許を持った有識者の方いらっしゃいましたら助けてください。

nonceなくてもまあ一定は平気〜とかそういう安心できる情報お待ちしてます。まあなんかこういうのoptionalぽい扱いされがちなんだけどclient側ちゃんと検証しろよってMUSTで書かれてたのでええんだっけ?となった次第

google sign inの公式ドキュメント通りに実装したらリプレイ攻撃に対して対抗策がない!なんてことになってるなら世界のアプリのgoogle sign inはそこそこの割合リプレイ攻撃やれっぞということになるし、流石にそんなことない気はしている。

なんかmobile client文脈ならではの、例えば攻撃者がIdPから返される値を傍受することが何らかの理由で非常に難しいから基本的にリプレイ攻撃は考慮しなくていいんじゃよみたいな、安心できる理屈がほしいので有識者は是非twitter DMなりこの記事へのブコメなりでぼくを助けてください。twitterhttps://twitter.com/convto です。

JS SDKとかを考えると裏側のWeb API自体はnonce対応してるんだろうからちゃちゃっと渡せるようにしてほしいな〜

感想

どちらにせよ普通にoptionalとしてnonce指定できたほうがいいと思うので、どっかにissue立てようかなぁ〜

追記

インターネットから知見が集まり、Android版はnonce渡せそう(または取得できそう)なことがわかった!
ぼくが見てたのは auth.api.signin だったけど、どうやら新しく auth.api.identity というやつがありそっちを使えば取得できるっぽい!
https://developers.google.com/android/reference/com/google/android/gms/auth/api/identity/GetSignInIntentRequest

全体的にGoogle Identity Serviceとかいう新しいsign inのサービス?がでてるっぽくそっちを使えばもろもろ整備されてるよう。

なんだけどiOSはやっぱ調べたライブラリ使ってて指定できない気がするんだよなぁ