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 以降
  • 新しいアプリ ID を作成できる Apple Developer アカウント
  • App Attest をサポートする iOS/iPadOS デバイス(App Attest API の利用可能性を参照)

2. スターター プロジェクトを入手する

Firebase Quickstarts for iOS リポジトリには、さまざまな 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) アプリのターゲットの [全般] タブを開きます。次に、[Frameworks, Libraries, and Embedded Content] セクションで [+] ボタンをクリックします。
  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 Authentication を構成します。
  • 保護する Realtime Database インスタンスを初期化します。
  • App Check を構成します。

プロジェクトを作成する

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

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

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

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. [公開] ボタンをクリックして、更新されたセキュリティ ルールを有効にします。

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

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

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

iOS アプリを接続する

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

  1. 新しいプロジェクトの [Project Overview] 画面で、[+ Add app] ボタンをクリックし、[iOS+] アイコンをクリックして、Firebase プロジェクトに新しい iOS アプリを追加します。
  2. アプリのバンドル ID を入力します(前のセクションで定義したものを使用します。たとえば com.acme.samples.firebase.quickstart.DatabaseExample などです。これは一意の識別子でなければなりません)。
  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. [ログイン方法] タブを選択します。
  4. [ネイティブ プロバイダ] で [メール/パスワード] を選択します。
  5. [メール/パスワード] を有効にして、[保存] をクリックします。

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

  1. [Authentication] セクションの [Users] タブを開きます。
  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 を入力します(この ID は Apple Developer ポータルの [Membership] セクションで確認できます)。1645f7a369b678c2.png
  5. [保存] をクリックします。

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

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

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

Firebase App Check SDK を実際に使用して、クライアント コードを実装してみましょう。

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

  1. Xcode プロジェクトで、アプリ ターゲットの App Attest 機能を追加します。
  2. アプリ ターゲット設定の [Signing & Capabilities] タブを開きます。
  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 シミュレータのデバッグ証明書プロバイダを構成する

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. Firebase コンソールに戻り、[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 を使用していない古いバージョンのアプリを使用しているユーザーがまだいる場合に、アクセスチェックをまだ強制したくないときに便利です。

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

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

64e6a81fa979b635.png

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

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

不正なアプリで Realtime Database にアクセスしてみる

App Check の適用を実際に確認するには、次の手順を行います。

  1. DatabaseExampleApp のアプリ エントリ ポイントの init メソッドで App Check 登録コードをコメントアウトして、App Check 登録を無効にします。
  2. [Device] > [Erase All Content and Settings] を選択して、シミュレータをリセットします。これにより、シミュレータがワイプされ(デバイス トークンが無効になります)、
  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 を段階的にロールアウトする Codelab で、Remote Config を使用して App Check をユーザーに段階的にロールアウトする方法を学習する

その他のリソース

この Codelab で説明する設定はほとんどの場合に機能しますが、必要に応じて App Check を使用して柔軟性を高めることもできます。詳しくは、次のリンクをご覧ください。