Lance o Firebase App Check gradualmente usando a Configuração remota do Firebase

1. Introdução

Use o Firebase App Check com o App Attest para proteger seus serviços de back-end e verificar se as solicitações aos serviços do Firebase estão vindo do seu app autêntico.

Geralmente, é recomendável integrar os usuários gradualmente ao serviço do App Attest para evitar atingir os limites de cota. Para mais informações, consulte o artigo da Apple "Preparing to Use the App Attest Service" (em inglês) na documentação do Google Cloud.

A capacidade de lançar atualizações incrementais do app usando o recurso App Store Connect da Apple, conforme descrito em Como lançar uma atualização de versão em fases, pode facilitar o lançamento do App Check. Essa é uma solução simples e direta. No entanto, lançar a atualização de uma versão do app em etapas não permite que você controle o lançamento nem a alteração do comportamento de apps atualizados sem publicar uma nova versão.

Uma maneira de ter mais controle sobre o lançamento do App Check com o App Attest é usar a Configuração remota do Firebase para ativar o App Check com o App Attest para uma porcentagem dos usuários do app por vez. Isso pode ajudar a evitar a limitação dos servidores de atestado. Use o Google Analytics para observar o impacto do lançamento nos usuários.

O que você aprenderá

Neste codelab de várias etapas, você vai aprender a usar a Configuração remota do Firebase para implantar o App Check no seu app.

Este codelab usa um projeto do Firebase baseado no app de início rápido do DatabaseExample e integrado ao Firebase App Check, conforme descrito no codelab do Firebase App Check para plataformas da Apple. Com o app de início rápido do DatabaseExample, os usuários podem fazer login e adicionar postagens usando os recursos do Firebase Realtime Database.

Você também pode adaptar as etapas deste codelab para testar seu próprio app.

Pré-requisitos

O que é necessário

  • Xcode 12.5 ou mais recente
  • Para testes do App Attest:
    • Uma conta de desenvolvedor da Apple que permite criar novos identificadores de app
    • Um aplicativo com um ID explícito e com o recurso App Attest ativado. Consulte os artigos Registrar um ID de app e Ativar recursos de apps se precisar de ajuda com o processo.
    • Um dispositivo iOS/iPadOS compatível com o App Attest
  • Projeto do Firebase com:
  • Acesso ao projeto do Firebase associado ao seu app, com permissões para criar e gerenciar a Configuração remota e ver o Google Analytics

2. Criar um provedor de atestados personalizado

Nesta etapa, vamos criar uma classe de provedor personalizada para fornecer um token somente quando o App Attest estiver ativado. A Configuração remota depende de uma instância configurada do app Firebase, e o provedor personalizado que você implementar nesta etapa funciona como o marcador de posição para concluir a configuração.

Para concluir as etapas a seguir, adicione Firebase, FirebaseRemoteConfig e FirebaseAnalytics na seção Estruturas, bibliotecas e conteúdo incorporado do app no Xcode. Para conferir um exemplo, consulte o codelab Firebase App Check para plataformas da Apple.

  1. Crie um arquivo "MyAppCheckProvider" que é uma subclasse de NSObject em conformidade com o protocolo AppCheckProvider.
  2. Inclua um método getToken() vazio que você vai preencher mais tarde.

Confira o exemplo de código a seguir para a classe de provedor personalizada com o método getToken() vazio.

// MyAppCheckProvider.swift

import Firebase
import FirebaseAnalytics
import FirebaseAppCheck
import FirebaseRemoteConfig

class MyAppCheckProvider: NSObject, AppCheckProvider {
  func getToken(completion handler: @escaping (AppCheckToken?, Error?) -> Void) {}
}

Para instanciar AppAttestProvider, é necessário transmitir uma instância do FirebaseApp correspondente. Crie uma propriedade armazenada para ela e a aceite como um parâmetro inicializador:

// MyAppCheckProvider.swift

import Firebase
import FirebaseAnalytics
import FirebaseAppCheck
import FirebaseRemoteConfig

class MyAppCheckProvider: NSObject, AppCheckProvider {
  // Firebase app instance served by the provider.
  let firebaseApp: FirebaseApp

  // The App Check provider factory should pass the FirebaseApp instance.
  init(app: FirebaseApp) {
    self.firebaseApp = app
    super.init()
  }

  func getToken(completion handler: @escaping (AppCheckToken?, Error?) -> Void) {}
}

Encaminhar a solicitação de token para o provedor do App Attest

Agora você tem tudo para encaminhar a solicitação de token para o provedor do App Attest no método getToken().

Observação: saiba mais sobre o método getToken() na Referência do framework do FirebaseAppCheck.

Adicione o seguinte código ao método getToken():

// MyAppCheckProvider.swift

import Firebase
import FirebaseAnalytics
import FirebaseAppCheck
import FirebaseRemoteConfig

class MyAppCheckProvider: NSObject, AppCheckProvider {
  // Firebase app instance served by the provider.
  let firebaseApp: FirebaseApp

  // The App Check provider factory should pass the FirebaseApp instance.
  init(app: FirebaseApp) {
    self.firebaseApp = app
    super.init()
  }

  private lazy var appAttestProvider = AppAttestProvider(app: firebaseApp)

  func getToken(completion handler: @escaping (AppCheckToken?, Error?) -> Void) {
    // Fetch App Attest flag from Remote Config
    let remoteConfig = RemoteConfig.remoteConfig(app: firebaseApp)
    remoteConfig.fetchAndActivate { remoteConfigStatus, error in
      // Get App Attest flag value
      let appAttestEnabled = remoteConfig.configValue(forKey: "AppAttestEnabled").boolValue

      guard appAttestEnabled else {
        // Skip attestation if App Attest is disabled. Another attestation
        // method like DeviceCheck may be used instead of just skipping.
        handler(nil, MyProviderError.appAttestIsDisabled)
        return
      }

      // Try to obtain an App Attest provider instance and fail if cannot
      guard let appAttestProvider = self.appAttestProvider else {
        handler(nil, MyProviderError.appAttestIsUnavailable)
        return
      }

      // If App Attest is enabled for the app instance, then forward the
      // Firebase App Check token request to the App Attest provider
      appAttestProvider.getToken(completion: handler)
    }
  }
}

enum MyProviderError: Error {
  case appAttestIsDisabled
  case appAttestIsUnavailable
  case unexpected(code: Int)
}

O código anterior verifica um parâmetro booleano AppAttestEnabled da Configuração remota. Esse parâmetro será criado mais adiante no codelab. Se o valor for falso, o código vai falhar, indicando que o App Check não foi lançado no dispositivo atual. Se o valor for verdadeiro, o código tentará obter um provedor do App Attest e falhará se não conseguir. Se essas verificações de erro forem bem-sucedidas, o código vai encaminhar a solicitação de token para o provedor do App Attest.

Adicionar eventos do Google Analytics

Ao adicionar eventos do Analytics, você recebe insights melhores sobre o sucesso do lançamento do App Check. O Analytics vai ajudar a determinar se o App Attest precisa ser ativado para um público maior.

Registre dois eventos do Google Analytics: AppAttestSuccess em caso de sucesso e AppAttestFailure em caso de falha. Esses dois eventos do Google Analytics podem ajudar a acompanhar o sucesso do lançamento do App Check e decidir se um lançamento maior deve ser feito.

func getToken(completion handler: @escaping (AppCheckToken?, Error?) -> Void) {
  // Fetch Remote Config.
  let remoteConfig = RemoteConfig.remoteConfig(app: firebaseApp)
  remoteConfig.fetchAndActivate { remoteConfigStatus, error in
    // Get App Attest flag value from Remote Config.
    let appAttestEnabled = remoteConfig.configValue(forKey: "AppAttestEnabled").boolValue

    guard appAttestEnabled else {
      // Skip attestation if App Attest is disabled. Another attestation
      // method like DeviceCheck may be used instead of just skipping.
      handler(nil, MyProviderError.appAttestIsDisabled)
      return
    }

    // Try to obtain an App Attest provider instance and fail otherwise.
    guard let appAttestProvider = self.appAttestProvider else {
      handler(nil, MyProviderError.appAttestIsUnavailable)
      return
    }

    // If App Attest is enabled for the app instance, then forward the
    // Firebase App Check token request to the App Attest provider.
    appAttestProvider.getToken { token, error in
      // Log an Analytics event to track attestation success rate.
      let appAttestEvent: String
      if (token != nil && error == nil) {
        appAttestEvent = "AppAttestSuccess"
      } else {
        appAttestEvent = "AppAttestFailure"
      }
      Analytics.logEvent(appAttestEvent, parameters: nil)

      // Pass the result to the handler
      handler(token, error)
    }
  }
}

3. Atualizar a classe Provider Factory

Depois de implementar a lógica para encaminhar a solicitação de token ao provedor do App Attest e adicionar alguns eventos do Google Analytics, atualize a MyAppCheckProviderFactory.class que você criou no codelab App Check para plataformas da Apple. Essa classe será destinada ao provedor de depuração do App Check para simuladores. Caso contrário, ela segmentará seu provedor personalizado.

Edite o seguinte código na classe MyAppCheckProviderFactory que você criou no codelab Verificação de app do Firebase para plataformas da Apple:

// 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
      if #available(iOS 14.0, *) {
        // Use your custom App Attest provider on real devices.
        return MyAppCheckProvider(app: app)
      } else {
        return DeviceCheckProvider(app: app)
      }
      #endif
  }
}

Confirme se você definiu AppCheckProviderFactory antes de configurar FirebaseApp:

// DatabaseExampleApp.swift

import SwiftUI
import Firebase
import FirebaseAppCheck

@main
struct DatabaseExampleApp: App {
  init() {
    AppCheck.setAppCheckProviderFactory(MyAppCheckProviderFactory())
    FirebaseApp.configure()
  }

  // ...
}

4. Adicionar um parâmetro da Configuração remota ao Console do Firebase

Agora, adicione o parâmetro AppAttestEnabled da Configuração remota ao console do Firebase. Seu método getToken exige esse parâmetro.

Para criar um parâmetro da Configuração remota no console do Firebase:

  1. Abra a Configuração remota do seu projeto e clique em Adicionar parâmetro. Se você estiver usando a Configuração remota pela primeira vez, clique em Criar configuração.
  2. No campo Nome do parâmetro (chave), insira AppAttestEnabled.
  3. No menu suspenso Tipo de dados, selecione Booleano.
  4. No menu suspenso Valor padrão, selecione falso.

Como criar um parâmetro da Configuração remota no console do Firebase

Antes de clicar em "Salvar", crie um valor condicional para 10% dos usuários:

  1. Clique em Adicionar novo > Valor condicional > Criar nova condição.
  2. No campo Nome, insira um nome para a condição.
  3. Em Aplicável se..., selecione Usuário na porcentagem aleatória, <= e digite 10 no campo %.
  4. Clique em Criar condição.

Como definir uma condição da Configuração remota no console do Firebase

Defina o valor condicional como true para que o App Attest seja lançado para 10% dos usuários.

  1. Defina o valor como true para a condição que você acabou de criar.
  2. Clique em Salvar.

Como analisar o parâmetro da Configuração remota no Console do Firebase

Quando terminar, publique as mudanças da Configuração remota.

Testar o lançamento no seu dispositivo

Para testar os diferentes valores de sinalização da Configuração remota no seu dispositivo sem modificar o código do app, configure um experimento com o parâmetro AppAttestEnabled seguindo o tutorial Criar experimentos da Configuração remota do Firebase com testes A/B. A seção do tutorial Validar seu experimento em um dispositivo de teste explica como atribuir valores diferentes ao dispositivo de teste.

A etapa final é usar o Google Analytics para monitorar o sucesso do lançamento do App Attest.

5. Analise o sucesso do lançamento do AppCheck

É possível medir o sucesso do lançamento no painel "Eventos do Google Analytics". Aguarde os eventos AppAttestSuccess e AppAttestFailure. Pode levar até 24 horas para que os eventos apareçam no painel. Como alternativa, você pode ativar a depuração e usar o DebugView para conferir os eventos de depuração mais rapidamente.

Também é possível monitorar o painel do Crashlytics para verificar aumentos nas taxas de falhas. Para saber mais sobre como adicionar o Crashlytics ao seu app, consulte Primeiros passos do Firebase Crashlytics.

Quando a maioria dos eventos AppAttestSuccess e poucos eventos AppAttestFailure forem exibidos, isso é um bom sinal de que é possível aumentar a porcentagem de usuários com o App Attest ativado modificando a condição no parâmetro da Configuração remota AppAttestEnabled.

Como analisar eventos do Google Analytics no Console do Firebase

Opcional: aproveite o público-alvo do Google Analytics

Se você quiser aproveitar ainda mais o evento AppAttestEnabled do Google Analytics, crie um público-alvo do Google Analytics para acompanhar os usuários com AppAttestEnabled definido como verdadeiro.

O App Attest foi lançado com o iOS 14.0. Alguns dos seus usuários podem não estar nessa versão e, portanto, não estão qualificados para o App Attest. Você pode registrar outro evento do Google Analytics para rastrear esses usuários e segmentar esse público para outro método de atestado, como o DeviceCheck.

Opcional: usar o Crashlytics para monitorar falhas

Para entender melhor a estabilidade do app durante o lançamento, use o Firebase Crashlytics para monitorar falhas e erros não fatais.

6. Parabéns!

Você lançou o App Check com a Configuração remota 🎉

Recursos adicionais: