🛡

【Flutter】App Check を導入して Firebase を守ろう!【2023年9月】

2023/09/20に公開

eye-catch

はじめに

下の画像を見てください。これはとあるアプリの Firebase Console の App Check の Cloud Firestore のモニタリング画面です。この画面で 不正リクエストがどのくらいあるかが確認できます。

え?小さくてよくわかりませんか?もう少し拡大してみましょう。

↓拡大してみました。不正リクエストは 2% ありました。30日間で不正リクエストは57万回あったということです!

さらに Authentication は 18% も不正リクエストがありました!

これは、どうにかしないといけない。。。ということで、最近 Firebase App Check を個人開発した Flutter アプリに導入したので、導入手順について紹介します!

コードの修正は簡単ですが、Firebase 側の設定がなかなか難解ですし、公式サイト は手順がひとつにまとまっていなくてわかりづらかったので、記事にまとめてみました。参考になればうれしいです!

App Check とは

App Check とは、未承認のアプリが Firebase の各リソースにアクセスすることを防ぐことで、不正使用から保護する Firebase のサービスです。

App Check を導入しない場合、次のようなリスクが考えられます。

  • 大量リクエストを投げつけられて、高額な Firebase の利用料金を請求される
  • データベースを改ざんされる
  • 課金コンテンツを無料で使われてしまう

特に google-services.jsonGoogleService-Info.plist などの Firebase への接続情報をパブリックリポジトリに置いている場合はリスクが高まるので App Check を導入してセキュリティを高めましょう!

App Check の導入とは別に、Storage や Firestore のセキュリティルールはちゃんとしておきましょう。セキュリティルールは Kosuke さんの次の記事がためになります!

https://qiita.com/KosukeSaigusa/items/18217958c581eac9b245

App Check の仕組み

App Check を使用すると、アプリから Firebase の各リソースへのリクエストに証明書プロバイダの証明書を添付します。Firebase コンソール上で App Check の適用を有効にすると、未承認のリクエストや有効な証明書がないアプリからのリクエストが拒否されます。

2023 年 9 月 20 日現在、App Check は次の Firebase リソースに対応しています。

  • Cloud Firestore
  • Cloud Storage
  • Cloud Functions (呼び出し可能関数)
  • Authentication(ベータ版)
  • Realtime Database

詳細については次の公式サイトをご参照ください。

https://firebase.google.com/docs/app-check?hl=ja

それでは App Check の導入方法について説明していきます!

環境

Flutter 3.13.4 • channel stable • https://github.com/flutter/flutter.git
Framework • revision 367f9ea16b (6 days ago) • 2023-09-12 23:27:53 -0500
Engine • revision 9064459a8b
Tools • Dart 3.1.2 • DevTools 2.25.0

Firebase 自体の設定方法は本記事では割愛しています。Firebase 自体の導入方法は次の記事を参考にしてみてください!

https://zenn.dev/susatthi/articles/20220904-151314-flutter-fire-flavor

App Check の導入手順

アプリに App Check を導入する

まず、アプリに App Check を導入します。pubspec.yaml に firebase_app_check を追加してください。

pubspec.yaml
dependencies:
  flutter:
    sdk: flutter
  firebase_core: ^2.15.1
  firebase_auth: ^4.9.0
  cloud_firestore: ^4.9.1
+  firebase_app_check: ^0.1.5

次の初期化コードを Firebase.initializeApp() の後に追加します。これにより、Firestore などの Firebase サービスを使用する前に App Check の初期化が実行されます。各プラットフォーム向けの初期化処理は別途紹介します。

main.dart
Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();

  // Firebase の初期化
  await Firebase.initializeApp(
    options: DefaultFirebaseOptions.currentPlatform,
  );

+  // App Check の初期化
+  await FirebaseAppCheck.instance.activate();
+
  runApp(const MyApp());
}

各プラットフォーム向けに App Check を導入する

各プラットフォームへの App Check の導入手順の概要は次のとおりです。

  1. Firebase に証明書プロバイダを登録する
  2. アプリの App Check アクティベーション処理を修正する
  3. デバッグトークンを登録する

Android と iOS の証明書プロバイダの導入手順を紹介します。すみません、Web は割愛します。

プラットフォーム 証明書プロバイダ
Android Play Integrity
iOS DeviceCheck

Android ( Play Integrity ) の導入手順

Firebase に証明書プロバイダを登録する

Google Play Console の 設定>アプリの完全性 を開き、「アプリの署名」タブを選択してください。表示されている「アプリ署名鍵の証明書」と「アップロード鍵の証明書」の 2 つの SHA-256 証明書のフィンガープリントを取得しておきます。

Firebase コンソールの App Check セクションを開き、アプリタブを選択してください。Android アプリの「登録」ボタンを押下し、「Play Integrity」を選択して、先ほど取得した 2 つの SHA-256 フィンガープリント を入力して保存します。

これで、Play Integrity の登録は完了です!

アプリの App Check アクティベーション処理を修正する

次に、App Check の初期化コードを次のように修正します。リリースビルド時は Play Integrity を利用し、デバッグビルド時はデバッグトークンを利用するように設定しましょう。

main.dart
  // App Check の初期化
  await FirebaseAppCheck.instance.activate(
+    androidProvider: kReleaseMode ? AndroidProvider.playIntegrity : AndroidProvider.debug,
  );

デバッグトークンを登録する

デバッグビルドで Android を実行すると次のようなログが表示されるので、デバッグトークンを取得しておきます。

D/com.google.firebase.appcheck.debug.internal.DebugAppCheckProvider( 5480): Enter this debug secret into the allow list in the Firebase Console for your project: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx

Firebase コンソールの App Check セクションを開き、アプリタブを選択してください。Android アプリの「デバッグトークンを管理」ボタンを押下してください。

「デバッグ トークンを追加」ボタンを押下して、先ほど取得したデバッグトークンを登録します。

これで、Android のデバッグトークンの登録は完了です!

iOS ( DeviceCheck )

Firebase に証明書プロバイダを登録する

まず、DeviceCheck の秘密鍵を作成します。

Apple デベロッパーサイトの「Certificates, Identifiers & Profiles」を開き、Keys の「+」ボタンを押下してください。

DeviceCheck にチェックを入れて秘密鍵を作成し、Key ID を控え、秘密鍵(P8)ファイルをダウンロードしておきます。

Firebase コンソールの App Check セクションを開き、アプリタブを選択してください。iOS アプリの「登録」ボタンを押下し、「DeviceCheck」を選択して、秘密鍵(P8)ファイルをアップロードし、Key ID を入力して保存します。

アプリの App Check アクティベーション処理を修正する

Android と同様に、App Check の初期化コードを次のように修正します。

main.dart
  // App Check の初期化
  await FirebaseAppCheck.instance.activate(
+    appleProvider: kReleaseMode ? AppleProvider.deviceCheck : AppleProvider.debug,
  );

デバッグトークンを登録する

デバッグビルドで iOS を実行すると次のようなログが表示されるので、デバッグトークンを取得しておきます。

Firebase App Check Debug Token: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx

Firebase コンソールの App Check セクションを開き、アプリタブを選択してください。次に、iOS アプリの「デバッグトークンを管理」ボタンを押下してください。

「デバッグ トークンを追加」ボタンを押下して、先ほど取得したデバッグトークンを保存します。

これで、iOS のデバッグトークンの登録は完了です!

App Check の適用を有効にする

ここまでの手順を終えても、まだ不正なリクエストを拒否できていません。 不正なリクエストを拒否できるように、Firebase の App Check の適用を有効にしましょう。

Firebase コンソールの App Check セクションを開き、API タブを選択してください。適用を開始したい API を選択し(ここでは Cloud Firestore を選択しました)、「適用」ボタンを押下します。これで適用は完了です!しばらくすると不正なリクエストを拒否し始めます!

不正なリクエストが拒否されることを確認する

ちゃんと設定と実装ができていれば、デバッグトークンを登録していないデバイスからのリクエストは拒否されるはずなので動作確認してみましょう。

App Check の適用を有効にした上で、デバッグトークンを登録していないデバイス(シミュレータ)から Firestore などにアクセスしてみましょう。次のように、Permission Denied のエラーが返ってくれば OK です!これを期にちゃんとエラーハンドリングも実装しましょうね。

[cloud_firestore/permission-denied] The caller does not have permission to execute the specified operation.

うまくいかない場合は時間をおいて試してみるとよいかもしれません。

正規のリクエストが許可されることを確認する

Google Play Console や App Store (TestFlight) からインストールしたアプリから Firebase にちゃんとアクセスできることを確認しましょう!

また、デバッグトークンを登録したデバイスからのリクエストが許可されることも確認しましょう!うまくいかない場合は時間をおいて試してみるとよいかもしれません。

運用時の注意点

App Check を導入すると、開発メンバーが追加したときにデバッグトークンを取得して Firebase に登録する作業が必要になるので、オンボーディングの手順に組み込んでおく必要があります。もう少し簡単に管理ができるようになれば嬉しい。。。

サンプルコードを公開しています

今回ご紹介したサンプルコードを公開しています。是非参考にしてください!

https://github.com/susatthi/flutterfire-sample-app-check

最後に

Flutter 大学という Flutter エンジニアに特化した学習コミュニティに所属しています。オンラインでわいわい議論したり、Flutter の最新情報をゲットしたりできます!ぜひ Flutter 界隈を盛り上げていきましょう!

https://flutteruniv.com?invite_id=9hsdZHg0qtaMIr6RPRulAaRJfA83

あわせて読みたい

https://note.com/rect_angle/n/n27899e6ce00f

Discussion