App Checkの仕組み - Firebase App Checkによる不正利用対策
はじめに
株式会社つみきの田中と申します。映画・ドラマ・アニメのレビューサービス「Filmarks(フィルマークス)」で、モバイルアプリエンジニアとして開発を担当しています。
モバイルアプリやWebアプリケーションを開発していると、APIの不正利用対策が重要な課題となります。特に、ボットによる大量リクエストや不正なクライアントからの攻撃を防ぐ必要があります。
Firebase App Checkは、このような不正利用からバックエンドサービスを保護するためのサービスです。本記事は、Firebase App Checkの導入を検討するにあたり、各プロバイダーの利用制限やFirebase App Checkの動作原理をまとめたものです。
Firebase App Checkとは
Firebase App Checkは、Firebaseのバックエンドサービス(Firestore、Cloud Functions、Cloud Storage等)を不正利用から保護するためのサービスで、Firebase以外のバックエンドサービス(自分たちで用意したAPIなど)の保護にも利用できます。
iOSやAndroid、Web等の各プラットフォームでは、クライアントを検証しバックエンドサービスを不正利用から保護する目的で、専用の認証APIが提供されています。
Firebase App Checkの特徴は、これらの各プラットフォームで提供されているクライアント認証APIを利用し、アプリの正当性を検証することです。Firebase App Checkでは、これらのプラットフォーム固有の認証APIをプロバイダーと呼びます。
サポートされているプロバイダー
Firebase App Checkは、以下のプラットフォーム固有の証明プロバイダーに対応しています。
- iOS: App Attest または Device Check
- Android: Play Integrity
- Web: reCAPTCHA v3
Firebase App Checkの基本的な仕組み
上記のプロバイダーを直接利用する場合、バックエンド側で各プロバイダーが提供する認証APIごとに実装を行う必要があります。 しかし、Firebase App Checkを導入すると、代わりにプロバイダーとのやりとりを行ってくれるため、実装の手間を大幅に削減できます。
App Checkを利用しない場合と利用する場合の比較を、図で表すと以下のようになります(具体的なやりとりは省略しています)
Firebase App Checkを利用しない場合(左図)
従来の実装で、各プロバイダー(App Attest、Play Integrity)との直接的なやり取りが必要です。
プロバイダーとのやりとりが複雑で、Firebase App Check無しだと以下のような実装が必要になります:
バックエンド
- nonceを発行するためのAPI実装と発行したnonceの保持
- Androidから受け取ったIntegrity Tokenの検証とnonceが正しいかの検証
- iOSから受け取ったAttestationObject/AssertionObjectの検証とnonceが正しいかの検証
- App Attestの場合、token検証後に公開鍵とレシートをDBに保存し、以降検証用Tokenが来るたびに保存した内容を利用する
アプリ側
- バックエンドからnonceを取得
- プロバイダーから用意されたAPIにnonceをセットしてリクエストし、Tokenを取得
- 受け取ったTokenをリクエストヘッダーに付与してリクエスト
nonceの実装や保持、Play Integrity用/App Attest用のToken検証方法の分離、さらにApp Attestではサーバー側での追加実装が必要になります。
Firebase App Checkを利用する場合(右図)
プロバイダーとのやりとりを代わりに行ってくれるため、必要な実装が大幅に削減されます。
バックエンド
- 受け取ったFirebase App Check Tokenの検証
アプリ
- Firebase App Checkの初期化処理
- Firebase App Checkから受け取ったTokenをリクエストヘッダーに付与してリクエスト
Firebase App Checkを利用した方が実装コストが格段に低くなりますね。
Firebase App Checkがアプリに対して行う検証
Firebase App Check自体が直接検証を行っているわけではなく、各プラットフォームのプロバイダーがアプリの検証を行います。検証項目はプロバイダーによって異なります。
App Attest(iOS)
- App Storeからインストールされたアプリか
- 改ざんされていないアプリか
- アプリから発行されたリクエストか
Play Integrity(Android)
- 正規のデバイスのものか
- Play Storeからインストールされたアプリか
- 改ざんされていないアプリか
- アプリから発行されたリクエストか
iOSの場合は、正しいiOSデバイスかどうかを検証するDevice Checkというサービスもありますが、アプリの検証にはApp Attestのみで十分です。
Firebase App Checkの認証フロー
Firebase App Checkの認証フローは以下のようになります:
- クライアント認証: アプリ側のFirebase App Check SDKがプロバイダーとやり取りを行い、アプリの信頼性を判定するためのトークンを取得
- Firebase App Check認証: プロバイダーから受け取ったトークンをFirebase App Checkサーバーに送信し、有効期限付きのFirebase App Checkトークンを取得
- APIリクエスト: 取得したFirebase App Checkトークンをリクエストヘッダーに付与してバックエンドAPIを呼び出し
- トークン検証: バックエンド側でFirebase App Checkトークンを検証し、正当性を確認
App AttestやPlay Integrityはnonceを使った検証も行うので、下図のようなフローになっていると思われます。
利用制限について
Firebase App Check自体は無料で利用できますが、プロバイダーが提供するクライアント認証APIには利用回数制限があり、推奨する使い方があります。
-
App Attest:
- 有効性を検証してもらう回数に利用制限を設けている(上限は明記されていない)
- iOSデバイス単位で一回限り行うため、段階的リリースを通じて徐々に検証できるバージョンを増やしていくことが推奨されている
-
Play Integrity:
- デフォルト1万回/日までが上限で、重要なAPIのみにクライアント認証を行うことを推奨している
- 上限緩和申請が可能
App Attest / Play Integrityの概要
Firebase App Checkが利用するプロバイダーがどのような検証を行っているかを説明します。
App Attestについて
概要
App Attestを利用すると、以下のことが検証できます:
- アプリが改ざんされていないか
- アプリから送られてきたリクエストが正当なものか
- アプリがApp Storeからインストールされたものか
アプリ側で発行した秘密鍵をAppleサーバーに検証してもらい、その公開鍵をバックエンドに保存して、以降APIのリクエストのたびに秘密鍵を使って生成した認証オブジェクトをサーバー側が公開鍵を使って検証する形になっています。
認証フロー
- App Attestの機能を利用し、公開鍵と秘密鍵のキーペアを生成
※このキーペアはデバイス上のSecure Enclaveに自動的に保存される - キーペア生成時にキーIDが返されるので、keychainに保存する
※生成されたキーIDはApp AttestがSecure Enclaveからキーペアを参照する際に必要になる - 自前サーバーにチャレンジ値を要求
- 自前サーバーはリクエストが来たら、任意のランダムな文字列もしくはUUIDを返す
- アプリ側は受け取ったチャレンジ値をHash化し、Appleのサーバー上にあるApp AttestサービスにHash値とKeyIDを渡して、生成したキーペアが有効なものかどうかを検証してもらう
- 検証が成功するとAppleから公開鍵やレシート情報が入った
AttestationObject
が返されるので、アプリ側はこのオブジェクトを自分のサーバーに送る - サーバーは受け取った
AttestationObject
を検証し、オブジェクトに埋め込まれた公開鍵とレシートを保存する
※デバイスを複数持つユーザーを考慮して複数の公開鍵とレシートを紐づけられるようにする必要あり
以降サーバーの保護したいAPIを利用するときに以下のやりとりをアプリとサーバー側が行います:
- アプリがサーバー側にチャレンジ値を要求
- サーバーはチャレンジ値をアプリに返す
- アプリはチャレンジ値と秘密鍵を使って
assertionObject
を生成しAPIに送る - サーバー側は保存した公開鍵を使って
assertionObject
を検証し、レスポンスを返す
利用回数がカウントされるタイミング
生成したKeyPairをAppleサーバーに送って検証する際にカウントされます。
※assertionObjectの生成は制限がありません
構成証明プロセスの推奨実行タイミング
基本的に一回のみです。生成したキーはアプリの再インストール、デバイスの移行、またはバックアップからのデバイスの復元等には耐えられないので、紛失した場合は最初からやり直す必要があります。
Play Integrity
概要
Play Integrity APIを利用すると、以下のことが検証できます:
- デバイスが正規のものか
- アプリがPlay Storeからインストールされたものか
- アプリが改ざんされていないか
- アプリから送られてきたリクエストが正当なものか
Play Integrity APIを利用すると判定結果がアプリに渡されるので、それをサーバーに検証してもらう形になっています。
認証フロー
以下がその認証フローです:
- 自前サーバーから
nonce
を取得
nonceを利用することにより、値の改ざんとリプレイ攻撃を防ぐ
具体的には、ランダムな値に改ざんを防ぎたい値を合わせてnonce
として利用する - アプリがPlay Integrity APIにIntegrity Tokenをリクエスト
リクエストにnonce
をセット - 受け取ったIntegrity Tokenを自前サーバーに渡す
※このIntegrityTokenにはnonceも含まれる - 自前サーバーがTokenを復元・検証を行う
Googleに復元・検証を任せる方法(推奨)と自分で復元・検証を行う方法がある
利用回数がカウントされるタイミング
Play Integrity APIを叩いた時にカウントされます。
構成証明プロセスの推奨実行タイミング
頻度が少なく重要なリクエスト(ログイン等)のたびに実行します。
Firebase App Checkが全APIにクライアント認証を仕込んでも耐えられるであろう理由
App AttestやPlay Integrityの仕組みを説明しましたが、それぞれ利用制限があることが分かりました。App Attestに関しては、段階的リリースを通じて徐々に反映していけば利用制限に引っかからず、全APIを保護することはできます。一方でPlay Integrityでは明確に利用回数制限があるため全APIを保護することは難しいです。
しかし、Firebase App Checkを使うことによって、全APIを保護することも可能になります。その理由について説明します。
Firebase App Checkトークンの有効期限と更新
Firebase App CheckトークンにはTTL(Time to Live)という有効期限が設定されており、デフォルトは1時間です。トークンの有効期限が残り半分になると、自動的に更新処理が実行されます。
TTLは30分から7日間の任意の値を設定可能ですが、セキュリティとパフォーマンスのバランスを考慮すると、1時間が妥当とされています。これは、そのトークンが外部に漏れてしまうと、そのトークンを利用してAPIの保護を通過してしまうため、長すぎない方がよいからです。
Firebase App Checkの動作としては、クライアント認証を通じてアプリが正常であるかどうかを確認し、その証明としてトークンを生成しています。そのトークンの有効期限が切れるまでは、そのトークンがFirebase App Checkが保証するものかどうかを検証します。期限が切れたら、またプロバイダーのクライアント認証を再度行ってクライアントが信頼できる状態かどうかを保つようになっています。実際にクライアント認証を行う回数は少ないです。
デフォルトでは1時間が有効期限でその半分の30分で更新されるので、1ユーザー/日最大でも48回(24時間 ÷ 30分 = 48回)しかクライアント認証が行われません。そのため、Play Integrityの上限に引っかかりにくい仕組みになっています。
まとめ
Firebase App Checkは、各プラットフォームのクライアント認証APIを統一的に利用できる強力なサービスです。プロバイダーとの直接的なやり取りを避けることで、実装の複雑さを大幅に削減できます。
特に、iOSのApp AttestとAndroidのPlay Integrityを統一的に扱える点は大きなメリットです。本記事がFirebase App Check導入の検討にあたって参考になれば幸いです。
おわりに
本稿では、不正対策として強力な武器になり得るFirebase App Checkを紹介しました。
このように、つみきではセキュリティ対策にも力を入れ、ユーザーが安心してサービスを使える環境づくりを大切にしています。こうした思いに共感し、良いアプリを共に作っていくエンジニアを募集しています!
- 国内最大級!Filmarksのアプリを支えるAndroidエンジニア募集!
- Ruby on Rails|Filmarksのバックエンドエンジニア募集!
- Filmarksの基盤を支える!AWS×インフラエンジニア募集!
Discussion