Apple プラットフォーム用の Firebase App Check

1. はじめに

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

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

App Check は、プラットフォーム固有のサービスを使用して、アプリやデバイスの整合性を検証します。これらのサービスは、構成証明プロバイダーと呼ばれます。そのようなプロバイダーの 1 つは Apple のApp Attestサービスで、App Check はこれを使用して Apple のアプリとデバイスの信頼性を検証できます。

何を構築するか

このコードラボでは、既存のサンプル アプリケーションに App Check を追加して強制し、プロジェクトの Realtime Database が不正なアプリやデバイスによるアクセスから保護します。

学べること

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

必要なもの

  • Xcode 13.3.1以降
  • 新しいアプリ識別子を作成できる Apple 開発者アカウント
  • App Attest をサポートする iOS/iPadOS デバイス ( App Attest API の利用可能性についてはこちらをご覧ください)

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

iOS 用 Firebase クイックスタート リポジトリには、さまざまな Firebase 製品をデモするサンプル アプリが含まれています。このコードラボのベースとして、SwiftUI 用の Firebase Database Quickstart アプリを使用します。

コマンドラインからiOS 用 Firebase Quickstarts リポジトリのクローンを作成します。

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

Xcode で Realtime Database SwiftUI Quickstart アプリ プロジェクトを開きます。

cd database/DatabaseExampleSwiftUI/DatabaseExample
xed .

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

  1. Swift Package Manager がプロジェクトの依存関係を解決するまで待ちます。
  2. DatabaseExample (iOS)アプリ ターゲットの[全般]タブを開きます。次に、 「フレームワーク、ライブラリ、埋め込みコンテンツ」セクションで、 「+」ボタンをクリックします。
  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.swiftで、 FirebaseAppCheckをインポートし、 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認証を設定します。
  • 保護する Realtime Database インスタンスを初期化します。
  • アプリチェックを設定します。

プロジェクトを作成する

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

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

リアルタイムデータベースインスタンスの作成

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

  1. 「データベースの作成」ボタンをクリックして、データベース作成ワークフローを開始します。
  2. データベースのデフォルトの場所 ( us-central1 ) を変更しないで、 「次へ」をクリックします。
  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)ターゲットを選択し、 「署名と機能」タブを開きます。
  3. 「DatabaseExample (iOS) の署名には開発チームが必要です」というエラー メッセージが表示されます。
  4. バンドル識別子を一意の識別子に更新します。これを実現する最も簡単な方法は、Web サイトの逆引きドメイン名 ( com.acme.samples.firebase.quickstart.DatabaseExampleなど) を使用することです (この ID は使用しないでください。代わりに独自の一意の ID を選択してください)。
  5. 開発チームを選択してください。
  6. Xcode に「プロビジョニング プロファイル: Xcode 管理対象プロファイル」と、このラベルの横に小さな情報アイコンが表示されれば、すべてがうまくいったことがわかります。このアイコンをクリックすると、プロビジョニング プロファイルに関する詳細が表示されます。

iOS アプリを接続する

アプリの接続の詳細な説明については、 iOS プロジェクトへの Firebase の追加に関するドキュメントを参照してください。開始するには、Firebase コンソールで次の主な手順に従います。

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

Firebase認証を構成する

ふう!ここまでの設定はかなり大変ですが、しっかり待ってください。 Firebase を初めて使用する場合は、ワークフローの重要な部分を見てきましたので、すぐに慣れるでしょう。

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

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

  1. Firebase コンソールで、コンソールの[認証]セクションを開きます。
  2. [開始]をクリックして、プロジェクトの Firebase Authentication を設定します。
  3. [サインイン方法]タブを選択します。
  4. [ネイティブ プロバイダー]セクションで[電子メール/パスワード]を選択します。
  5. 電子メール/パスワードを有効にして、 [保存]をクリックします。

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

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

アプリを試してみる

Xcode に戻り、iOS シミュレーターでアプリケーションを実行します。作成したテスト ユーザーの電子メールとパスワードを使用してサインインします。サインインしたら、投稿を作成したり、既存の投稿にコメントを投稿したり、投稿にスタ​​ーを付けたり外したりできます。

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 プロジェクトでアプリ ターゲットのアプリ認証機能を追加します。
  2. アプリのターゲット設定で「署名と機能」タブを開きます
  3. + 」ボタンをクリックします
  4. ダイアログで、アプリの認証機能を見つけて選択しますae84cd988a5fab31.png
  5. 前の手順を実行すると、ファイルDatabaseExample (iOS).entitlements Xcode プロジェクトのルート フォルダーに表示されます。
  6. DatabaseExample (iOS).entitlementsファイルで、 App Attest Environmentキーの値をproduction.

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

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

8. iOS シミュレーターのデバッグ認証プロバイダーを構成する

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

アプリに 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 シミュレーターからデバッグ シークレットを取得します。

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

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

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

  1. Firevbase コンソールに戻り、 「App Check」セクションに移動します。
  2. [アプリ]タブで、アプリをクリックして詳細を展開します。
  3. オーバーフロー メニューで、 [デバッグ トークンの管理] を選択します。 d77c8ff768a00b4b.png
  4. Xcode コンソールからコピーしたシークレットを追加し、 「保存」をクリックします。 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. 確認ダイアログの情報を読み、 「強制」をクリックします。

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

不正なアプリを使用してリアルタイム データベースにアクセスしてみる

App Check の実施を確認するには、次の手順に従います。

  1. DatabaseExampleAppのアプリ エントリ ポイントのinitメソッドにある App Check 登録コードをコメント アウトして、App Check 登録をオフにします。
  2. [デバイス] > [すべてのコンテンツと設定を消去]を選択して、シミュレータをリセットします。これにより、シミュレータが消去されます (そしてデバイス トークンが無効になります)。
  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 を使用して Firebase App Check を段階的にロールアウトするコードラボで、Remote Config を使用して App Check をユーザーに段階的にロールアウトする方法を学びます。

これらは役立つと思われるその他のリソースです

このコードラボで説明されている設定はほとんどの場合に機能しますが、App Check を使用すると、必要に応じてさらに柔軟に対応できます。詳細については、次のリンクを確認してください。