OTOBANK Engineering Blog

オトバンクはコンテンツが大好きなエンジニアを募集しています!

Google Cloud Identity-Aware Proxy (Cloud IAP) のJWTをPHPで検証しつつ、中身について少し勉強する

お久しぶりです。 @kalibora です。

いきなりですが、 Google Cloud Identity-Aware Proxy (以下Cloud IAP) 便利ですね。

詳細は Cloud Identity-Aware Proxy  |  Identity-Aware Proxy  |  Google Cloud この辺りを読んでもらえばいいとして、

知らない人にざっくり説明すると、

既存のWebアプリにこの機能を設定すれば、必ずGoogleログインが必須になり、 ログインしたユーザーがあらかじめ許可されたユーザーであれば、既存のWebアプリに通して(プロキシして)くれる。

というような機能です。

G Suite を使っている会社であれば、社員がみんな Google アカウントを持っているので、 社内の管理系ツールなどに認証機能がなくとも、この機能を使えばあっという間に認証機能のできあがり。なので楽ですね。

はい。で、そういった機能で必ず必要になるのが、

  • どうやって認証したユーザーのIDをアプリ側で取得するか?
  • その改ざんの防止

です。

認証したユーザーが誰なのか?が分からなければアプリ側でそれに応じた細かな制御も出来ないですし、 誰なのか?が改ざんされたら元も子もありません。

その辺りの説明は

署名済みヘッダーによるアプリの保護  |  Identity-Aware Proxy のドキュメント  |  Google Cloud

にあるのですが、ここで使用しているのが最近よく聞く JWT (Json Web Token) です。

具体的にはプロキシされたHTTPリクエストのヘッダーには必ず x-goog-iap-jwt-assertion を含んでおり、

この値が JWT (もっと具体的に言うと JWS の Compact 形式)となっています。

JWS は 署名付きメッセージのことで Compact は よく見るドット2つで連携した形式のことみたいですが、

私が適当な事言うよりも 複雑に関係しあうJWTまわりの仕様を見る: JWS (JSON Web Signature) - 理系学生日記 ここを見たほうがよいです。

ともかくメッセージがあって、その改ざん防止のために署名してるんだな。くらいの理解でひとまずここはいきましょう。

はい、それでその大事なメッセージ本体の部分はペイロードといいます。

このペイロード部分にユーザーIDである sub と、メールアドレス email が含まれているので、

アプリ側では JWT を適当なライブラリでパースし、その中身を取って使えばいいのです。

ちなみに改ざん防止の検証が不要なら、ライブラリさえいりません。

下記のワンライナーは JWT のヘッダ部分をパースする例です。

$ php -r 'var_dump(base64_decode(strtr("eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6InJUbGstZyJ9", "-_", "+"), true));'
Command line code:1:
string(42) "{"alg":"ES256","typ":"JWT","kid":"rTlk-g"}"

ドットで区切られたパーツ部分は、単なる Base64Url形式なので、こんなシンプルな実装で取得できるんですね。

とはいえ、改ざん防止を検証しないなんてことはありえないので、ちゃんと検証しましょう。

また、 署名済みヘッダーによるアプリの保護  |  Identity-Aware Proxy のドキュメント  |  Google Cloud にあるように、署名の検証だけでなく、ヘッダやペイロードの中身が制約に従っているかも確認する必要があります。

ちなみに私は Introduction - JWT Framework というライブラリを使って実装し、下記のパッケージとして公開しました。

kalibora/google-cloud-iap-jwt-validator - Packagist

記事中の間違いやバグなどあれば報告していただけると幸いです。 それではまた。