Fügen Sie Ihrer iOS-App die Multi-Faktor-Authentifizierung hinzu

Wenn Sie mit Identity Platform auf Firebase Authentication aktualisiert haben, können Sie Ihrer iOS-App eine mehrstufige SMS-Authentifizierung hinzufügen.

Die Multi-Faktor-Authentifizierung erhöht die Sicherheit Ihrer App. Während Angreifer häufig Passwörter und soziale Konten kompromittieren, ist das Abfangen einer Textnachricht schwieriger.

Bevor Sie beginnen

  1. Aktivieren Sie mindestens einen Anbieter, der die Multi-Faktor-Authentifizierung unterstützt. Jeder Anbieter unterstützt MFA, außer Telefonauthentifizierung, anonyme Authentifizierung und Apple Game Center.

  2. Stellen Sie sicher, dass Ihre App die E-Mails der Benutzer überprüft. MFA erfordert eine E-Mail-Bestätigung. Dies verhindert, dass sich böswillige Akteure mit einer E-Mail-Adresse, die ihnen nicht gehört, für einen Dienst registrieren und dann den tatsächlichen Eigentümer durch Hinzufügen eines zweiten Faktors aussperren.

Multi-Faktor-Authentifizierung aktivieren

  1. Öffnen Sie die Seite Authentifizierung > Anmeldemethode der Firebase-Konsole.

  2. Aktivieren Sie im Abschnitt „Erweitert“ die SMS-Multifaktor-Authentifizierung .

    Sie sollten auch die Telefonnummern eingeben, mit denen Sie Ihre App testen möchten. Die Registrierung von Testtelefonnummern ist zwar optional, wird jedoch dringend empfohlen, um eine Drosselung während der Entwicklung zu vermeiden.

  3. Wenn Sie die Domäne Ihrer App noch nicht autorisiert haben, fügen Sie sie der Zulassungsliste auf der Seite „Authentifizierung“ > „Einstellungen“ der Firebase-Konsole hinzu.

Verifizierung Ihrer App

Firebase muss überprüfen, ob SMS-Anfragen von Ihrer App kommen. Sie können dies auf zwei Arten tun:

  • Stille APNs-Benachrichtigungen : Wenn Sie einen Benutzer zum ersten Mal anmelden, kann Firebase eine stille Push-Benachrichtigung an das Gerät des Benutzers senden. Die Authentifizierung kann fortgesetzt werden, wenn die App die Benachrichtigung erhält. Beachten Sie, dass Sie den Benutzer ab iOS 8.0 nicht mehr bitten müssen, Push-Benachrichtigungen zuzulassen, um diese Methode verwenden zu können.

  • reCAPTCHA-Überprüfung : Wenn Sie keine stille Benachrichtigung senden können (z. B. weil der Benutzer die Hintergrundaktualisierung deaktiviert hat oder Sie Ihre App im iOS-Simulator testen), können Sie reCAPTCHA verwenden. In vielen Fällen löst sich das reCAPTCHA automatisch und ohne Benutzerinteraktion auf.

Stille Benachrichtigungen verwenden

So aktivieren Sie APNs-Benachrichtigungen für die Verwendung mit Firebase:

  1. Aktivieren Sie in Xcode Push-Benachrichtigungen für Ihr Projekt.

  2. Laden Sie Ihren APNs-Authentifizierungsschlüssel mit der Firebase-Konsole hoch (Ihre Änderungen werden automatisch auf Google Cloud Firebase übertragen). Wenn Sie Ihren APNs-Authentifizierungsschlüssel noch nicht haben, lesen Sie „Konfigurieren von APNs mit FCM“, um zu erfahren, wie Sie ihn erhalten.

    1. Öffnen Sie die Firebase-Konsole .

    2. Navigieren Sie zu Projekteinstellungen .

    3. Wählen Sie die Registerkarte „Cloud-Messaging“ aus.

    4. Klicken Sie unter „APNs-Authentifizierungsschlüssel“ im Abschnitt „iOS-App-Konfiguration“ auf „Hochladen “.

    5. Wählen Sie Ihren Schlüssel aus.

    6. Fügen Sie die Schlüssel-ID für den Schlüssel hinzu. Sie finden die Schlüssel-ID unter Zertifikate, Identifikatoren und Profile im Apple Developer Member Center .

    7. Klicken Sie auf Hochladen .

Wenn Sie bereits über ein APNs-Zertifikat verfügen, können Sie stattdessen das Zertifikat hochladen.

Verwendung der reCAPTCHA-Verifizierung

So aktivieren Sie das Client-SDK für die Verwendung von reCAPTCHA:

  1. Öffnen Sie Ihre Projektkonfiguration in Xcode.

  2. Doppelklicken Sie in der linken Baumansicht auf den Projektnamen.

  3. Wählen Sie Ihre App im Abschnitt „Ziele“ aus.

  4. Wählen Sie die Registerkarte „Info“ .

  5. Erweitern Sie den Abschnitt URL-Typen .

  6. Klicken Sie auf die Schaltfläche + .

  7. Geben Sie Ihre umgekehrte Client-ID in das Feld „URL-Schemata“ ein. Sie finden diesen Wert in der Konfigurationsdatei GoogleService-Info.plist als REVERSED_CLIENT_ID .

Nach Abschluss sollte Ihre Konfiguration etwa wie folgt aussehen:

Benutzerdefinierte Schemata

Optional können Sie die Art und Weise anpassen, wie Ihre App den SFSafariViewController oder UIWebView bei der Anzeige des reCAPTCHA darstellt. Erstellen Sie dazu eine benutzerdefinierte Klasse, die dem FIRAuthUIDelegate Protokoll entspricht, und übergeben Sie sie an verifyPhoneNumber:UIDelegate:completion: .

Auswählen eines Anmeldemusters

Sie können wählen, ob Ihre App eine Multi-Faktor-Authentifizierung erfordert und wie und wann Sie Ihre Benutzer registrieren. Einige häufige Muster sind:

  • Registrieren Sie den zweiten Faktor des Benutzers im Rahmen der Registrierung. Verwenden Sie diese Methode, wenn Ihre App eine mehrstufige Authentifizierung für alle Benutzer erfordert. Beachten Sie, dass ein Konto über eine verifizierte E-Mail-Adresse verfügen muss, um einen zweiten Faktor zu registrieren. Daher muss Ihr Registrierungsablauf dies berücksichtigen.

  • Bieten Sie bei der Registrierung eine überspringbare Option zur Registrierung eines zweiten Faktors an. Apps, die die Multi-Faktor-Authentifizierung fördern, aber nicht erfordern möchten, bevorzugen möglicherweise diesen Ansatz.

  • Bieten Sie die Möglichkeit, einen zweiten Faktor über die Konto- oder Profilverwaltungsseite des Benutzers anstelle des Anmeldebildschirms hinzuzufügen. Dies minimiert die Reibung während des Registrierungsprozesses und stellt gleichzeitig die Multi-Faktor-Authentifizierung für sicherheitsempfindliche Benutzer zur Verfügung.

  • Erfordern Sie das schrittweise Hinzufügen eines zweiten Faktors, wenn der Benutzer auf Funktionen mit erhöhten Sicherheitsanforderungen zugreifen möchte.

Einschreiben eines zweiten Faktors

So registrieren Sie einen neuen sekundären Faktor für einen Benutzer:

  1. Authentifizieren Sie den Benutzer erneut.

  2. Bitten Sie den Benutzer, seine Telefonnummer einzugeben.

  3. Holen Sie sich eine Multi-Faktor-Sitzung für den Benutzer:

    Schnell

    authResult.user.multiFactor.getSessionWithCompletion() { (session, error) in
      // ...
    }
    

    Ziel c

    [authResult.user.multiFactor
      getSessionWithCompletion:^(FIRMultiFactorSession * _Nullable session,
                                NSError * _Nullable error) {
        // ...
    }];
    
  4. Senden Sie eine Bestätigungsnachricht an das Telefon des Benutzers. Stellen Sie sicher, dass die Telefonnummer mit einem führenden + und keinen anderen Satzzeichen oder Leerzeichen formatiert ist (z. B. +15105551234 ).

    Schnell

    // Send SMS verification code.
    PhoneAuthProvider.provider().verifyPhoneNumber(
      phoneNumber,
      uiDelegate: nil,
      multiFactorSession: session) { (verificationId, error) in
        // verificationId will be needed for enrollment completion.
    }
    

    Ziel c

    // Send SMS verification code.
    [FIRPhoneAuthProvider.provider verifyPhoneNumber:phoneNumber
                                          UIDelegate:nil
                                  multiFactorSession:session
                                          completion:^(NSString * _Nullable verificationID,
                                                        NSError * _Nullable error) {
        // verificationId will be needed for enrollment completion.
    }];
    

    Obwohl dies nicht erforderlich ist, empfiehlt es sich, die Benutzer im Voraus darüber zu informieren, dass sie eine SMS-Nachricht erhalten und dass Standardtarife gelten.

    Die Methode verifyPhoneNumber() startet den App-Verifizierungsprozess im Hintergrund mithilfe einer stillen Push-Benachrichtigung. Wenn keine stille Push-Benachrichtigung verfügbar ist, wird stattdessen eine reCAPTCHA-Challenge ausgegeben.

  5. Sobald der SMS-Code gesendet wurde, bitten Sie den Benutzer, den Code zu bestätigen. Verwenden Sie dann ihre Antwort, um ein PhoneAuthCredential zu erstellen:

    Schnell

    // Ask user for the verification code. Then:
    let credential = PhoneAuthProvider.provider().credential(
      withVerificationID: verificationId,
      verificationCode: verificationCode)
    

    Ziel c

    // Ask user for the SMS verification code. Then:
    FIRPhoneAuthCredential *credential = [FIRPhoneAuthProvider.provider
                                           credentialWithVerificationID:verificationID
                                           verificationCode:kPhoneSecondFactorVerificationCode];
    
  6. Initialisieren Sie ein Assertionsobjekt:

    Schnell

    let assertion = PhoneMultiFactorGenerator.assertion(with: credential)
    

    Ziel c

    FIRMultiFactorAssertion *assertion = [FIRPhoneMultiFactorGenerator assertionWithCredential:credential];
    
  7. Schließen Sie die Anmeldung ab. Optional können Sie einen Anzeigenamen für den zweiten Faktor angeben. Dies ist nützlich für Benutzer mit mehreren zweiten Faktoren, da die Telefonnummer während des Authentifizierungsvorgangs maskiert wird (z. B. +1******1234).

    Schnell

    // Complete enrollment. This will update the underlying tokens
    // and trigger ID token change listener.
    user.multiFactor.enroll(with: assertion, displayName: displayName) { (error) in
      // ...
    }
    

    Ziel c

    // Complete enrollment. This will update the underlying tokens
    // and trigger ID token change listener.
    [authResult.user.multiFactor enrollWithAssertion:assertion
                                         displayName:nil
                                          completion:^(NSError * _Nullable error) {
        // ...
    }];
    

Der folgende Code zeigt ein vollständiges Beispiel für die Registrierung eines zweiten Faktors:

Schnell

let user = Auth.auth().currentUser
user?.multiFactor.getSessionWithCompletion({ (session, error) in
  // Send SMS verification code.
  PhoneAuthProvider.provider().verifyPhoneNumber(
    phoneNumber,
    uiDelegate: nil,
    multiFactorSession: session
  ) { (verificationId, error) in
    // verificationId will be needed for enrollment completion.
    // Ask user for the verification code.
    let credential = PhoneAuthProvider.provider().credential(
      withVerificationID: verificationId!,
      verificationCode: phoneSecondFactorVerificationCode)
    let assertion = PhoneMultiFactorGenerator.assertion(with: credential)
    // Complete enrollment. This will update the underlying tokens
    // and trigger ID token change listener.
    user?.multiFactor.enroll(with: assertion, displayName: displayName) { (error) in
      // ...
    }
  }
})

Ziel c

FIRUser *user = FIRAuth.auth.currentUser;
[user.multiFactor getSessionWithCompletion:^(FIRMultiFactorSession * _Nullable session,
                                              NSError * _Nullable error) {
    // Send SMS verification code.
    [FIRPhoneAuthProvider.provider
      verifyPhoneNumber:phoneNumber
      UIDelegate:nil
      multiFactorSession:session
      completion:^(NSString * _Nullable verificationID, NSError * _Nullable error) {
        // verificationId will be needed for enrollment completion.

        // Ask user for the verification code.
        // ...

        // Then:
        FIRPhoneAuthCredential *credential =
            [FIRPhoneAuthProvider.provider credentialWithVerificationID:verificationID
                                                        verificationCode:kPhoneSecondFactorVerificationCode];
        FIRMultiFactorAssertion *assertion =
            [FIRPhoneMultiFactorGenerator assertionWithCredential:credential];

        // Complete enrollment. This will update the underlying tokens
        // and trigger ID token change listener.
        [user.multiFactor enrollWithAssertion:assertion
                                  displayName:displayName
                                    completion:^(NSError * _Nullable error) {
            // ...
        }];
    }];
}];

Glückwunsch! Sie haben erfolgreich einen zweiten Authentifizierungsfaktor für einen Benutzer registriert.

Benutzer mit einem zweiten Faktor anmelden

So melden Sie einen Benutzer mit der Zwei-Faktor-SMS-Verifizierung an:

  1. Melden Sie den Benutzer mit seinem ersten Faktor an und erhalten Sie dann eine Fehlermeldung, die darauf hinweist, dass eine mehrstufige Authentifizierung erforderlich ist. Dieser Fehler enthält einen Resolver, Hinweise zu den registrierten zweiten Faktoren und eine zugrunde liegende Sitzung, die beweist, dass sich der Benutzer erfolgreich mit dem ersten Faktor authentifiziert hat.

    Wenn der erste Faktor des Benutzers beispielsweise eine E-Mail-Adresse und ein Passwort wäre:

    Schnell

    Auth.auth().signIn(
      withEmail: email,
      password: password
    ) { (result, error) in
      let authError = error as NSError
      if authError?.code == AuthErrorCode.secondFactorRequired.rawValue {
        // The user is a multi-factor user. Second factor challenge is required.
        let resolver =
          authError!.userInfo[AuthErrorUserInfoMultiFactorResolverKey] as! MultiFactorResolver
        // ...
      } else {
        // Handle other errors such as wrong password.
      }
    }
    

    Ziel c

    [FIRAuth.auth signInWithEmail:email
                         password:password
                       completion:^(FIRAuthDataResult * _Nullable authResult,
                                    NSError * _Nullable error) {
        if (error == nil || error.code != FIRAuthErrorCodeSecondFactorRequired) {
            // User is not enrolled with a second factor and is successfully signed in.
            // ...
        } else {
            // The user is a multi-factor user. Second factor challenge is required.
        }
    }];
    

    Wenn der erste Faktor des Benutzers ein Verbundanbieter wie OAuth ist, fangen Sie den Fehler nach dem Aufruf von getCredentialWith() ab.

  2. Wenn der Benutzer mehrere sekundäre Faktoren registriert hat, fragen Sie ihn, welchen er verwenden soll. Sie können die maskierte Telefonnummer mit resolver.hints[selectedIndex].phoneNumber und den Anzeigenamen mit resolver.hints[selectedIndex].displayName erhalten.

    Schnell

    // Ask user which second factor to use. Then:
    if resolver.hints[selectedIndex].factorID == PhoneMultiFactorID {
      // User selected a phone second factor.
      // ...
    } else if resolver.hints[selectedIndex].factorID == TotpMultiFactorID {
      // User selected a TOTP second factor.
      // ...
    } else {
      // Unsupported second factor.
    }
    

    Ziel c

    FIRMultiFactorResolver *resolver =
        (FIRMultiFactorResolver *) error.userInfo[FIRAuthErrorUserInfoMultiFactorResolverKey];
    
    // Ask user which second factor to use. Then:
    FIRPhoneMultiFactorInfo *hint = (FIRPhoneMultiFactorInfo *) resolver.hints[selectedIndex];
    if (hint.factorID == FIRPhoneMultiFactorID) {
      // User selected a phone second factor.
      // ...
    } else if (hint.factorID == FIRTOTPMultiFactorID) {
      // User selected a TOTP second factor.
      // ...
    } else {
      // Unsupported second factor.
    }
    
  3. Senden Sie eine Bestätigungsnachricht an das Telefon des Benutzers:

    Schnell

    // Send SMS verification code.
    let hint = resolver.hints[selectedIndex] as! PhoneMultiFactorInfo
    PhoneAuthProvider.provider().verifyPhoneNumber(
      with: hint,
      uiDelegate: nil,
      multiFactorSession: resolver.session
    ) { (verificationId, error) in
      // verificationId will be needed for sign-in completion.
    }
    

    Ziel c

    // Send SMS verification code
    [FIRPhoneAuthProvider.provider
      verifyPhoneNumberWithMultiFactorInfo:hint
      UIDelegate:nil
      multiFactorSession:resolver.session
      completion:^(NSString * _Nullable verificationID, NSError * _Nullable error) {
        if (error != nil) {
            // Failed to verify phone number.
        }
    }];
    
  4. Sobald der SMS-Code gesendet wurde, bitten Sie den Benutzer, den Code zu überprüfen und ihn zum Erstellen eines PhoneAuthCredential zu verwenden:

    Schnell

    // Ask user for the verification code. Then:
    let credential = PhoneAuthProvider.provider().credential(
      withVerificationID: verificationId!,
      verificationCode: verificationCodeFromUser)
    

    Ziel c

    // Ask user for the SMS verification code. Then:
    FIRPhoneAuthCredential *credential =
        [FIRPhoneAuthProvider.provider
          credentialWithVerificationID:verificationID
                      verificationCode:verificationCodeFromUser];
    
  5. Initialisieren Sie ein Assertionsobjekt mit den Anmeldeinformationen:

    Schnell

    let assertion = PhoneMultiFactorGenerator.assertion(with: credential)
    

    Ziel c

    FIRMultiFactorAssertion *assertion =
        [FIRPhoneMultiFactorGenerator assertionWithCredential:credential];
    
  6. Lösen Sie die Anmeldung. Anschließend können Sie auf das ursprüngliche Anmeldeergebnis zugreifen, das die standardmäßigen anbieterspezifischen Daten und Authentifizierungsdaten enthält:

    Schnell

    // Complete sign-in. This will also trigger the Auth state listeners.
    resolver.resolveSignIn(with: assertion) { (authResult, error) in
      // authResult will also contain the user, additionalUserInfo, optional
      // credential (null for email/password) associated with the first factor sign-in.
    
      // For example, if the user signed in with Google as a first factor,
      // authResult.additionalUserInfo will contain data related to Google provider that
      // the user signed in with.
    
      // user.credential contains the Google OAuth credential.
      // user.credential.accessToken contains the Google OAuth access token.
      // user.credential.idToken contains the Google OAuth ID token.
    }
    

    Ziel c

    // Complete sign-in.
    [resolver resolveSignInWithAssertion:assertion
                              completion:^(FIRAuthDataResult * _Nullable authResult,
                                            NSError * _Nullable error) {
        if (error != nil) {
            // User successfully signed in with the second factor phone number.
        }
    }];
    

Der folgende Code zeigt ein vollständiges Beispiel für die Anmeldung eines Multi-Faktor-Benutzers:

Schnell

Auth.auth().signIn(
  withEmail: email,
  password: password
) { (result, error) in
  let authError = error as NSError?
  if authError?.code == AuthErrorCode.secondFactorRequired.rawValue {
    let resolver =
      authError!.userInfo[AuthErrorUserInfoMultiFactorResolverKey] as! MultiFactorResolver

    // Ask user which second factor to use.
    // ...

    // Then:
    let hint = resolver.hints[selectedIndex] as! PhoneMultiFactorInfo

    // Send SMS verification code
    PhoneAuthProvider.provider().verifyPhoneNumber(
      with: hint,
      uiDelegate: nil,
      multiFactorSession: resolver.session
    ) { (verificationId, error) in
      if error != nil {
        // Failed to verify phone number.
      }
      // Ask user for the SMS verification code.
      // ...

      // Then:
      let credential = PhoneAuthProvider.provider().credential(
        withVerificationID: verificationId!,
        verificationCode: verificationCodeFromUser)
      let assertion = PhoneMultiFactorGenerator.assertion(with: credential)

      // Complete sign-in.
      resolver.resolveSignIn(with: assertion) { (authResult, error) in
        if error != nil {
          // User successfully signed in with the second factor phone number.
        }
      }
    }
  }
}

Ziel c

[FIRAuth.auth signInWithEmail:email
                     password:password
                   completion:^(FIRAuthDataResult * _Nullable authResult,
                               NSError * _Nullable error) {
    if (error == nil || error.code != FIRAuthErrorCodeSecondFactorRequired) {
        // User is not enrolled with a second factor and is successfully signed in.
        // ...
    } else {
        FIRMultiFactorResolver *resolver =
            (FIRMultiFactorResolver *) error.userInfo[FIRAuthErrorUserInfoMultiFactorResolverKey];

        // Ask user which second factor to use.
        // ...

        // Then:
        FIRPhoneMultiFactorInfo *hint = (FIRPhoneMultiFactorInfo *) resolver.hints[selectedIndex];

        // Send SMS verification code
        [FIRPhoneAuthProvider.provider
          verifyPhoneNumberWithMultiFactorInfo:hint
                                    UIDelegate:nil
                            multiFactorSession:resolver.session
                                    completion:^(NSString * _Nullable verificationID,
                                                NSError * _Nullable error) {
            if (error != nil) {
                // Failed to verify phone number.
            }

            // Ask user for the SMS verification code.
            // ...

            // Then:
            FIRPhoneAuthCredential *credential =
                [FIRPhoneAuthProvider.provider
                  credentialWithVerificationID:verificationID
                              verificationCode:kPhoneSecondFactorVerificationCode];
            FIRMultiFactorAssertion *assertion =
                [FIRPhoneMultiFactorGenerator assertionWithCredential:credential];

            // Complete sign-in.
            [resolver resolveSignInWithAssertion:assertion
                                      completion:^(FIRAuthDataResult * _Nullable authResult,
                                                    NSError * _Nullable error) {
                if (error != nil) {
                    // User successfully signed in with the second factor phone number.
                }
            }];
        }];
    }
}];

Glückwunsch! Sie haben einen Benutzer erfolgreich mithilfe der Multi-Faktor-Authentifizierung angemeldet.

Was kommt als nächstes