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 デベロッパー アカウント
  • App Attest をサポートする iOS/iPadOS デバイス(App Attest API の提供状況をご確認ください)

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

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

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

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)は変更せずに、[次へ] をクリックします。
  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. Signing for DatabaseExample (iOS) require a development team」というエラー メッセージが表示されます。
  4. バンドル ID を一意の ID に更新します。最も簡単な方法は、ウェブサイトのリバース ドメイン名(例: com.acme.samples.firebase.quickstart.DatabaseExample)を使用することです(この ID は使用しないでください。代わりに独自の一意の ID を選択してください)。
  5. 開発チームを選択します。
  6. すべて正常に完了すると、Xcode に「プロビジョニング プロファイル: Xcode 管理プロファイル」と表示され、このラベルの横に小さな情報アイコンが表示されます。このアイコンをクリックすると、プロビジョニング プロファイルの詳細が表示されます。

iOS アプリを接続する

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

  1. 新しいプロジェクトの [プロジェクトの概要] 画面で、[+ アプリを追加] ボタンをクリックし、[iOS+] アイコンをクリックして、Firebase プロジェクトに新しい iOS アプリを追加します。
  2. アプリのバンドル ID を入力します(前のセクションで定義した 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 を入力します(これは 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. アプリのターゲット設定で [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 Simulator のデバッグ認証プロバイダを構成する

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 コンソールからコピーしたシークレットを追加し、[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. [デバイス] > [すべてのコンテンツと設定を消去] を選択して、シミュレータをリセットします。シミュレータがワイプされます(デバイス トークンが無効になります)。
  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 で説明する設定はほとんどのケースで機能しますが、必要に応じて App Check でより柔軟な設定を行うこともできます。詳しくは、次のリンクをご覧ください。