Apple プラットフォーム向け Firebase App Check

1. はじめに

Firebase App Check は、リクエストの送信元が正規のアプリやデバイスからであることを確認して、請求詐欺やフィッシングなどの不正行為からバックエンド リソースを保護します。Firebase サービスとお客様独自のバックエンド サービスの両方と連携して、リソースを安全に保ちます。

Firebase App Check の詳細については、Firebase のドキュメントをご覧ください。

App Check は、プラットフォーム固有のサービスを使用して、アプリやデバイスの完全性を検証します。これらのサービスは証明書プロバイダと呼ばれます。そのようなプロバイダの 1 つに、Apple の App Attest サービスがあります。App Check では、このサービスを使用して Apple のアプリやデバイスの真正性を確認できます。

作成するアプリの概要

この Codelab では、既存のサンプルアプリに App Check を追加して適用し、プロジェクトの Realtime Database が不正なアプリやデバイスからアクセスされないように保護します。

ラボの内容

  • Firebase App Check を既存のアプリに追加する方法
  • さまざまな Firebase App Check 証明書プロバイダをインストールする方法。
  • アプリの App Attest を構成する方法。
  • アプリの開発中にシミュレータでアプリをテストするようにデバッグ証明書プロバイダを構成する方法

必要なもの

  • Xcode 13.3.1 以降
  • 新しいアプリ識別子を作成できる Apple Developer アカウント
  • App Attest をサポートする iOS/iPadOS デバイス(App Attest API の提供状況をご確認ください)

2. スターター プロジェクトを取得する

iOS 向け Firebase クイックスタート リポジトリには、さまざまな Firebase プロダクトのデモを行うためのサンプルアプリが含まれています。この Codelab のベースとして、SwiftUI 用の Firebase Database クイックスタート アプリを使用します。

コマンドラインから iOS 向け Firebase クイックスタート リポジトリのクローンを作成します。

git clone https://github.com/firebase/quickstart-ios.git
cd quickstart-ios

Xcode で Realtime Database SwiftUI クイックスタート アプリ プロジェクトを開きます。

cd database/DatabaseExampleSwiftUI/DatabaseExample
xed .

3. アプリに App Check を追加する

  1. Swift Package Manager がプロジェクトの依存関係を解決するまで待ちます。
  2. DatabaseExample (iOS) アプリ ターゲットの [General] タブを開きます。[フレームワーク、ライブラリ、埋め込みコンテンツ] セクションで [+] ボタンをクリックします。
  3. FirebaseAppCheckを選択して追加します。

4. App Check プロバイダのファクトリを作成してインストールする

  1. Shared ファイル グループで、AppCheck という名前の新しいグループを追加します。
  2. このグループ内で、別のファイル(MyAppCheckProviderFactory.swift など)でファクトリ クラスを作成し、必ず DatabaseExample (iOS) ターゲットに追加します。
    import Firebase
    
    class MyAppCheckProviderFactory: NSObject, AppCheckProviderFactory {
      func createProvider(with app: FirebaseApp) -> AppCheckProvider? {
        #if targetEnvironment(simulator)
          // App Attest is not available on simulators.
          // Use a debug provider.
          return AppCheckDebugProvider(app: app)
        #else
          // Use App Attest provider on real devices.
          return AppAttestProvider(app: app)
        #endif
      }
    }
    
  3. 次に、DatabaseExampleApp.swiftFirebaseAppCheck をインポートし、MyAppCheckProviderFactory クラスのインスタンスを App Check プロバイダのファクトリとして設定します。
    import SwiftUI
    import FirebaseCore
    import FirebaseAppCheck
    
    @main
    struct DatabaseExampleApp: App {
      init() {
        // Set an instance of MyAppCheckProviderFactory as an App Check
        // provider factory before configuring Firebase.
        AppCheck.setAppCheckProviderFactory(MyAppCheckProviderFactory())
        FirebaseApp.configure()
      }
      ...
    }
    

5. Firebase プロジェクトを作成して構成する

iOS プロジェクトで App Check を使用するには、Firebase コンソールで次の手順に沿って操作します。

  • Firebase プロジェクトを設定します。
  • iOS アプリを Firebase プロジェクトに追加します。
  • Firebase Authentication を構成します。
  • 保護する Realtime Database インスタンスを初期化します。
  • App Check を構成します。

プロジェクトを作成する

まず、Firebase プロジェクトを作成する必要があります。

  1. Firebase コンソールで [プロジェクトを追加] を選択します。
  2. プロジェクトに App Check Codelab という名前を付けます。
  3. [続行] をクリックします。
  4. このプロジェクトで Google アナリティクスを無効にし、[プロジェクトを作成] をクリックします。

Realtime Database インスタンスを作成する

次に、Firebase コンソールの [Realtime Database] セクションに移動します。

  1. [データベースを作成] ボタンをクリックして、データベース作成ワークフローを開始します。
  2. データベースのデフォルトの場所(us-central1)は変更せずに、[Next] をクリックします。
  3. [ロックモード] が選択されていることを確認し、[有効にする] ボタンをクリックしてデータベースのセキュリティ ルールを有効にします。
  4. Realtime Database ブラウザの [ルール] タブに移動し、デフォルトのルールを次の内容に置き換えます。
    {
        "rules": {
            // User profiles are only readable/writable by the user who owns it
            "users": {
                "$UID": {
                    ".read": "auth.uid == $UID",
                    ".write": "auth.uid == $UID"
                }
            },
            // Posts can be read by anyone but only written by logged-in users.
            "posts": {
                ".read": true,
                ".write": "auth.uid != null",
                "$POSTID": {
                    // UID must match logged in user and is fixed once set
                    "uid": {
                        ".validate": "(data.exists() && data.val() == newData.val()) || newData.val() == auth.uid"
                    },
                    // User can only update own stars
                    "stars": {
                        "$UID": {
                            ".validate": "auth.uid == $UID"
                        }
                    }
                }
            },
            // User posts can be read by anyone but only written by the user that owns it,
            // and with a matching UID
            "user-posts": {
                ".read": true,
                "$UID": {
                    "$POSTID": {
                        ".write": "auth.uid == $UID",
                        ".validate": "data.exists() || newData.child('uid').val() == auth.uid"
                    }
                }
            },
            // Comments can be read by anyone but only written by a logged in user
            "post-comments": {
                ".read": true,
                ".write": "auth.uid != null",
                "$POSTID": {
                    "$COMMENTID": {
                        // UID must match logged in user and is fixed once set
                        "uid": {
                            ".validate": "(data.exists() && data.val() == newData.val()) || newData.val() == auth.uid"
                        }
                    }
                }
            }
        }
    }
    
  5. [公開] ボタンをクリックして、更新したセキュリティ ルールを有効にします。

iOS アプリを Firebase に接続できるように準備する

実機でサンプルアプリを実行できるようにするには、開発チームにプロジェクトを追加して、必要なプロビジョニング プロファイルを Xcode で管理できるようにする必要があります。サンプルアプリをデベロッパー アカウントに追加する手順は次のとおりです。

  1. Xcode のプロジェクト ナビゲータで DatabaseExample プロジェクトを選択します。
  2. DatabaseExample (iOS) ターゲットを選択し、[Signing & Capabilities] タブを開きます。
  3. Signing for DatabaseExample (iOS) require a development team」というエラー メッセージが表示されます。
  4. バンドル ID を一意の識別子に更新します。最も簡単な方法は、ウェブサイトのリバース ドメイン名(例: com.acme.samples.firebase.quickstart.DatabaseExample)を使用することです(この ID は使用しないでください。代わりに独自の一意の ID を選択してください)。
  5. 開発チームを選択します。
  6. 問題がなければ、Xcode に「Provisioning Profile: Xcode Managed Profile」と、このラベルの横に小さな情報アイコンが表示されます。このアイコンをクリックすると、プロビジョニング プロファイルの詳細が表示されます。

iOS アプリの接続

アプリの接続について詳しくは、Firebase を iOS プロジェクトに追加する方法のドキュメントをご覧ください。開始するには、Firebase コンソールで次の主要な手順を行います。

  1. 新しいプロジェクトの [Project Overview] 画面で、[+ Add app] ボタンをクリックし、[iOS+] アイコンをクリックして新しい iOS アプリを Firebase プロジェクトに追加します。
  2. アプリのバンドル ID を入力します(com.acme.samples.firebase.quickstart.DatabaseExample など、前のセクションで定義したものを使用します。ID は一意である必要があります)。
  3. [アプリを登録] をクリックします。
  4. Firebase は、アプリに必要なすべての Firebase メタデータを含む GoogleService-Info.plist ファイルを生成します。
  5. [GoogleService-Info.plist をダウンロード] をクリックしてファイルをダウンロードします。
  6. Xcode で、プロジェクトに GoogleService-Info.plist という名前のファイルがすでに含まれていることがわかります。まず、このファイルは削除してください。次のステップで、実際の Firebase プロジェクト用のファイルに置き換えます。
  7. 前の手順でダウンロードした GoogleService-Info.plist ファイルを Xcode プロジェクトのルートフォルダにコピーし、DatabaseExample (iOS) ターゲットに追加します。ファイル名が GoogleService-Info.plist になっていることを確認します。
  8. 登録フローの残りのステップをクリックします。サンプル プロジェクトはすでに正しくセットアップされているため、コードを変更する必要はありません。

Firebase Authentication を構成する

ぜひここまでのセットアップは完了ですが、もう少しお待ちください。Firebase を初めて使用する方にとっては、ワークフローの重要な部分を目にしたはずです。

次に、このアプリ用に Firebase Authentication を構成します。

認証メール/パスワード ログイン プロバイダを有効にする

  1. Firebase コンソールで、コンソールの [Authentication] セクションを開きます。
  2. [使ってみる] をクリックして、プロジェクトに Firebase Authentication を設定します。
  3. [Sign-in method] タブを選択します。
  4. [ネイティブ プロバイダ] で [メール/パスワード] を選択します。
  5. [メール/パスワード] を有効にして [保存] をクリックします。

テストユーザーを追加する

  1. [Authentication] セクションの [Users] タブを開きます。
  2. [ユーザーを追加] をクリックします。
  3. テストユーザーのメールとパスワードを指定し、[ユーザーを追加] をクリックします。

アプリを使ってみる

Xcode に戻り、iOS Simulator でアプリケーションを実行します。作成したテストユーザーのメールアドレスとパスワードでログインします。ログインしたら、投稿を作成したり、既存の投稿にコメントを投稿したり、投稿にスターをつけたり、スターをはずしたりします。

6. App Attest 証明書プロバイダを構成する

このステップでは、Firebase コンソールで App Attest プロバイダを使用するように App Check を構成します。

  1. Firebase コンソールで、[App Check] セクションに移動します。
  2. [開始] をクリックします。
  3. [アプリ] タブで、目的のアプリをクリックして詳細を開きます。
  4. [App Attest] をクリックして App Attest を構成し、Apple Developer アカウントのチーム ID を入力します(これは Apple Developer ポータルの [Membership] セクションにあります)。1645f7a369b678c2.png
  5. [保存] をクリックします。

これで、Firebase プロジェクトが新しいアプリに接続され、App Check が有効になりました。

これで、特定の構成証明サービスを構成する準備が整いました。このワークフローの詳細については、iOS で App Attest を使用して App Check を有効にするをご覧ください。

7. アプリケーション用に App Attest を構成する

それでは、Firebase App Check SDK を使って、クライアント コードを実装してみましょう。

まず、SDK が Apple の App Attest API を使用して、アプリから送信されたリクエストがアプリの正規インスタンスから送信されることを確認できるように、Xcode プロジェクトを構成する必要があります。

  1. Xcode プロジェクトに、アプリ ターゲットの App Attest 機能を追加します。
  2. アプリのターゲット設定で [署名と機能] タブを開く
  3. [+] ボタンをクリックします。
  4. ダイアログで、App Attest 機能 ae84cd988a5fab31.png を探して選択します。
  5. 前のステップを完了すると、Xcode プロジェクトのルートフォルダにファイル DatabaseExample (iOS).entitlements が表示されます。
  6. DatabaseExample (iOS).entitlements ファイルで、App Attest Environment キーの値を production. に変更します。

上記の手順を完了したら、物理の iOS デバイス(iPhone、iPad)でアプリを起動しても、Realtime Database に引き続きアクセスできます。後のステップで、App Check を適用します。これは、不正なアプリやデバイスから送信されるリクエストをブロックします。

このワークフローの詳細については、iOS で App Attest を使用して App Check を有効にするをご覧ください。

8. iOS Simulator のデバッグ認証プロバイダを構成する

Firebase App Check Debug プロバイダを使用すると、Firebase App Check を適用したアプリケーションを、信頼できない環境(iOS Simulator など)で開発プロセス中にテストできます。次に、デバッグ プロバイダを一緒に構成する必要があります。

アプリに Firebase デバッグ プロバイダをインストールする

オプション 1: ファクトリでデバッグ プロバイダのインスタンスを条件付きで作成する

この作業のほとんどは、App Check プロバイダのファクトリを作成したときに行いました。このステップでは、デバッグ プロバイダが生成したローカル デバッグ シークレットのロギングを追加します。これにより、デバッグのためにアプリのこのインスタンスを Firebase コンソールに登録できます。

MyAppCheckProviderFactory.swift を以下のコードに更新します。

import Firebase

class MyAppCheckProviderFactory: NSObject, AppCheckProviderFactory {
  func createProvider(with app: FirebaseApp) -> AppCheckProvider? {
#if targetEnvironment(simulator)
    // App Attest is not available on simulators.
    // Use a debug provider.
    let provider = AppCheckDebugProvider(app: app)

    // Print only locally generated token to avoid a valid token leak on CI.
    print("Firebase App Check debug token: \(provider?.localDebugToken() ?? "" )")

    return provider
#else
    // Use App Attest provider on real devices.
    return AppAttestProvider(app: app)
#endif
  }
}

このアプローチにより、環境に応じて App Check をより柔軟に構成できます。たとえば、App Attest を利用できない OS バージョンでは、DeviceCheck などの他の証明書プロバイダやカスタム証明書プロバイダを使用できます。以下の例をご覧ください。

import Firebase

class MyAppCheckProviderFactory: NSObject, AppCheckProviderFactory {
  func createProvider(with app: FirebaseApp) -> AppCheckProvider? {
      #if targetEnvironment(simulator)
      // App Attest is not available on simulators.
      // Use a debug provider.
      let provider = AppCheckDebugProvider(app: app)

      // Print only locally generated token to avoid a valid token leak on CI.
      print("Firebase App Check debug token: \(provider?.localDebugToken() ?? "" )")

      return provider
      #else
      if #available(iOS 14.0, *) {
        // Use App Attest provider on real devices.
        return AppAttestProvider(app: app)
      } else {
        return DeviceCheckProvider(app: app)
      }
      #endif
  }
}

オプション 2: AppCheckDebugProviderFactory をインストールする

より簡単なケースでは、Firebase アプリケーション インスタンスを構成する前に、AppCheckDebugProviderFactory を一時的または条件付きでインストールできます。

init() {
#if targetEnvironment(simulator)
  let providerFactory = AppCheckDebugProviderFactory()
#else
  let providerFactory = MyAppCheckProviderFactory()
#endif

  AppCheck.setAppCheckProviderFactory(providerFactory)

  FirebaseApp.configure()
}

これにより、独自の App Check プロバイダ ファクトリを作成するためのコードを数行の手間で省くことができます。

Firebase コンソールでデバッグ シークレットを登録する

iOS Simulator からデバッグ シークレットを取得する

  1. AppCheckDebugProviderFactory(上記のオプション 2)をインストールする場合は、アプリの起動引数に -FIRDebugEnabled を追加して、アプリのデバッグ ロギングを有効にする必要があります。f1c6b477a373e144.png
  2. シミュレータでアプリを実行する
  3. Xcode コンソールでデバッグ シークレットを見つけます。コンソールのフィルタ(d4c65af93e369c55.png)を使用すると、すばやく見つけることができます。

注: デバッグ シークレットはアプリの初回起動時にシミュレータ用に生成され、ユーザーのデフォルトに保存されます。アプリの削除、シミュレータのリセット、または別のシミュレータの使用を行うと、新しいデバッグ シークレットが生成されます。新しいデバッグ シークレットを必ず登録してください。

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

  1. Firevbase コンソールに戻り、[App Check] セクションに移動します。
  2. [アプリ] タブで、目的のアプリをクリックして詳細を開きます。
  3. オーバーフロー メニューで [デバッグ トークンを管理] を選択します(d77c8ff768a00b4b.png)。
  4. Xcode コンソールからコピーしたシークレットを追加し、[Save ] をクリックします。f845c97b86f694d0.png

この手順を完了すると、App Check が適用されている場合でも、シミュレータでアプリを利用できるようになります。

注: デバッグ プロバイダは、デバッグ シークレットの漏洩を防止するために特別に設計されています。現在のアプローチでは、デバッグ シークレットをソースコードに保存する必要はありません。

このフローについて詳しくは、iOS のデバッグ プロバイダで App Check を使用するのドキュメントをご覧ください。

9. Firebase Realtime Database に対して App Check の適用を有効にする

現時点では、アプリは実際のデバイスの AppAttestProvider を返す AppCheckProviderFactory を宣言します。実機で実行する場合、アプリは構成証明を実行し、結果を Firebase バックエンドに送信します。ただし、Firebase バックエンドは引き続き、あらゆるデバイス、iOS シミュレータ、スクリプトなどからのリクエストを受け入れます。このモードは、App Check を使用していない古いバージョンのアプリを使用しているユーザーがいて、まだアクセス チェックを適用したくない場合に便利です。

次に、App Check の適用を有効にして、正規のデバイスからのみ Firebase アプリにアクセスできるようにする必要があります。Firebase プロジェクトで適用を有効にすると、App Check を統合していない古いアプリ バージョンは動作しなくなります。

  1. Firebase コンソールの [App Check] セクションで、[Realtime Database] をクリックして詳細を開きます。
  2. [適用] をクリックします。

64e6a81fa979b635.png

  1. 確認ダイアログの情報を確認し、[適用] をクリックします。

これらの手順を完了すると、正当なアプリのみがデータベースにアクセスできるようになります。その他のアプリはすべてブロックされます。

不正なアプリを使用して Realtime Database にアクセスしてみてください

App Check の適用結果を確認する手順は次のとおりです。

  1. App Check の登録を無効にするには、DatabaseExampleApp のアプリ エントリ ポイントの init メソッドで App Check 登録コードをコメントアウトします。
  2. [Device] > [消去] > [すべてのコンテンツと設定を消去] を選択して、シミュレータをリセットします。シミュレータがワイプされます(デバイス トークンが無効になります)。
  3. シミュレータでアプリを再度実行します。
  4. 次のエラー メッセージが表示されます。
    [FirebaseDatabase][I-RDB034005] Firebase Database connection was forcefully killed by the server.  Will not attempt reconnect. Reason: Invalid appcheck token.
    

App Check を再度有効にする手順は次のとおりです。

  1. DatabaseExampleApp の App Check 登録コードのコメント化を解除します。
  2. アプリを再起動します。
  3. Xcode のコンソールに表示されている新しい App Check トークンをメモします。
  4. Firebase コンソールのアプリの App Check 設定でデバッグ トークンを登録します。
  5. アプリを再実行します。
  6. エラー メッセージが表示されなくなり、アプリに新しい投稿やコメントを追加できるようになります。

10. お疲れさまでした

9785d32f18b995d2.gif

ここでは、以下を行う方法を学びました。

  • App Check を既存のプロジェクトに追加する
  • アプリの製品版用に App Attest 証明書プロバイダを構成する
  • シミュレータでアプリをテストするようにデバッグ証明書プロバイダを構成する
  • アプリのバージョンのロールアウトを監視して、Firebase プロジェクトに App Check を適用するタイミングを把握する
  • App Check の適用を有効にする

次のステップ

Firebase Remote Config の Codelab で Firebase App Check を段階的にロールアウトするで、Remote Config を使用してユーザーに App Check を段階的にロールアウトする方法を確認する

他にも役に立つと思われるリソースがあります

この Codelab で説明する設定は、ほとんどの場合に有効ですが、必要に応じてより柔軟に利用できます。詳細については、以下のリンクをご覧ください。