Thêm tính năng xác thực đa yếu tố TOTP vào ứng dụng iOS

Nếu đã nâng cấp lên tính năng Xác thực Firebase bằng Nền tảng nhận dạng, bạn có thể thêm mật khẩu một lần theo thời gian (TOTP) xác thực đa yếu tố (MFA) cho ứng dụng của bạn.

Xác thực Firebase với nền tảng danh tính cho phép bạn sử dụng TOTP làm yếu tố bổ sung cho MFA. Khi bật tính năng này, người dùng cố gắng đăng nhập vào ứng dụng của bạn sẽ thấy yêu cầu TOTP. Để tạo dữ liệu xác thực, họ phải sử dụng một ứng dụng xác thực có khả năng tạo mã TOTP hợp lệ, chẳng hạn như Google Authenticator.

Trước khi bắt đầu

  1. Hãy bật ít nhất một nhà cung cấp hỗ trợ MFA. Xin lưu ý rằng tất cả các nhà cung cấp ngoại trừ các tính năng hỗ trợ MFA hỗ trợ sau đây:

    • Xác thực điện thoại
    • Xác thực ẩn danh
    • Mã thông báo xác thực tuỳ chỉnh
    • Trung tâm trò chơi của Apple
  2. Đảm bảo ứng dụng của bạn xác minh địa chỉ email của người dùng. Tính năng xác thực đa yếu tố (MFA) yêu cầu phải có email xác minh. Thao tác này ngăn đối tượng độc hại đăng ký một dịch vụ bằng địa chỉ email họ không sở hữu và sau đó khoá chủ sở hữu của địa chỉ email đó bằng cách thêm yếu tố thứ hai.

  3. Nếu bạn chưa làm như vậy, hãy cài đặt Apple SDK của Firebase.

    TOTP MFA chỉ được hỗ trợ trên SDK Apple phiên bản 10.12.0 trở lên và chỉ trên iOS.

Bật TOTP MFA

Để bật TOTP làm yếu tố thứ hai, hãy sử dụng SDK dành cho quản trị viên hoặc gọi dự án điểm cuối REST của cấu hình.

Để dùng SDK dành cho quản trị viên, hãy làm như sau:

  1. Nếu bạn chưa làm như vậy, hãy cài đặt SDK Node.js dành cho quản trị viên của Firebase.

    TOTP MFA chỉ được hỗ trợ trên SDK Node.js dành cho quản trị viên Firebase phiên bản 11.6.0 và ở trên.

  2. Chạy lệnh sau:

    import { getAuth } from 'firebase-admin/auth';
    
    getAuth().projectConfigManager().updateProjectConfig(
    {
          multiFactorConfig: {
              providerConfigs: [{
                  state: "ENABLED",
                  totpProviderConfig: {
                      adjacentIntervals: NUM_ADJ_INTERVALS
                  }
              }]
          }
    })
    

    Thay thế đoạn mã sau:

    • NUM_ADJ_INTERVALS: Số cửa sổ liền kề khoảng thời gian ghi nhận TOTP từ 0 đến 10. Chiến lược phát hành đĩa đơn mặc định là 5.

      TOTP hoạt động bằng cách đảm bảo rằng khi hai bên (người chứng minh và người tạo OTP trong cùng một khoảng thời gian (thường là 30 giây) lâu), chúng sẽ tạo cùng một mật khẩu. Tuy nhiên, để phù hợp với đồng hồ giữa các bên và thời gian phản hồi của con người, bạn có thể định cấu hình TOTP để chấp nhận TOTP từ các cửa sổ liền kề.

Để bật TOTP MFA bằng API REST, hãy chạy lệnh sau:

curl -X PATCH "https://identitytoolkit.googleapis.com/admin/v2/projects/PROJECT_ID/config?updateMask=mfa" \
    -H "Authorization: Bearer $(gcloud auth print-access-token)" \
    -H "Content-Type: application/json" \
    -H "X-Goog-User-Project: PROJECT_ID" \
    -d \
    '{
        "mfa": {
          "providerConfigs": [{
            "state": "ENABLED",
            "totpProviderConfig": {
              "adjacentIntervals": NUM_ADJ_INTERVALS
            }
          }]
       }
    }'

Thay thế đoạn mã sau:

  • PROJECT_ID: Mã dự án.
  • NUM_ADJ_INTERVALS: Số khung thời gian khoảng thời gian, từ 0 đến 10. Giá trị mặc định là 5.

    TOTP hoạt động bằng cách đảm bảo rằng khi hai bên (người chứng minh và người tạo OTP trong cùng một khoảng thời gian (thường là 30 giây) lâu), chúng sẽ tạo cùng một mật khẩu. Tuy nhiên, để phù hợp với đồng hồ giữa các bên và thời gian phản hồi của con người, bạn có thể định cấu hình TOTP để chấp nhận TOTP từ các cửa sổ liền kề.

Chọn một hình thức đăng ký

Bạn có thể chọn xem ứng dụng của mình có cần xác thực đa yếu tố hay không, cũng như và thời điểm đăng ký người dùng. Sau đây là một số mẫu phổ biến:

  • Đăng ký yếu tố thứ hai của người dùng trong quá trình đăng ký. Sử dụng bản thảo này nếu ứng dụng của bạn yêu cầu xác thực đa yếu tố đối với tất cả người dùng.

  • Cung cấp lựa chọn có thể bỏ qua để đăng ký yếu tố thứ hai trong quá trình đăng ký. Nếu bạn muốn khuyến khích nhưng không yêu cầu xác thực đa yếu tố trong ứng dụng của mình, bạn có thể sử dụng phương pháp này.

  • Cho phép thêm yếu tố thứ hai từ tài khoản hoặc hồ sơ của người dùng trang quản lý thay vì màn hình đăng ký. Việc này giúp giảm thiểu rào cản trong quá trình đăng ký, trong khi vẫn thực hiện xác thực đa yếu tố dành cho những người dùng nhạy cảm về bảo mật.

  • Yêu cầu thêm dần yếu tố thứ hai khi người dùng muốn truy cập có yêu cầu bảo mật cao hơn.

Đăng ký người dùng tham gia TOTP MFA

Sau khi bạn bật TOTP MFA làm yếu tố thứ hai cho ứng dụng của mình, hãy triển khai phía máy khách logic để đăng ký người dùng tham gia TOTP MFA:

  1. Xác thực lại người dùng.

  2. Tạo mã bí mật TOTP cho người dùng đã xác thực:

    // Generate a TOTP secret.
    guard let mfaSession = try? await currentUser.multiFactor.session() else { return }
    guard let totpSecret = try? await TOTPMultiFactorGenerator.generateSecret(with: mfaSession) else { return }
    
    // Display the secret to the user and prompt them to enter it into their
    // authenticator app. (See the next step.)
    
  3. Hiển thị bí mật cho người dùng và nhắc họ nhập bí mật vào ứng dụng xác thực:

    // Display this key:
    let secret = totpSecret.sharedSecretKey()
    

    Ngoài việc hiển thị khóa bí mật, bạn có thể thử tự động thêm đường liên kết đó vào ứng dụng xác thực mặc định trên thiết bị. Để thực hiện việc này, hãy tạo một URI khoá tương thích với Google Authenticator, rồi truyền đến openInOTPApp(withQRCodeURL:):

    let otpAuthUri = totpSecret.generateQRCodeURL(
        withAccountName: currentUser.email ?? "default account",
        issuer: "Your App Name")
    totpSecret.openInOTPApp(withQRCodeURL: otpAuthUri)
    

    Sau khi người dùng thêm khoá bí mật của họ vào ứng dụng xác thực, ứng dụng sẽ khởi động tạo TOTP.

  4. Nhắc người dùng nhập TOTP mà ứng dụng xác thực của họ hiển thị và sử dụng mã này để hoàn tất đăng ký MFA:

    // Ask the user for a verification code from the authenticator app.
    let verificationCode = // Code from user input.
    
    // Finalize the enrollment.
    let multiFactorAssertion = TOTPMultiFactorGenerator.assertionForEnrollment(
        with: totpSecret,
        oneTimePassword: verificationCode)
    do {
        try await currentUser.multiFactor.enroll(
            with: multiFactorAssertion,
            displayName: "TOTP")
    } catch {
        // Wrong or expired OTP. Re-prompt the user.
    }
    

Đăng nhập cho người dùng bằng yếu tố thứ hai

Để đăng nhập người dùng bằng TOTP MFA, hãy sử dụng mã sau:

  1. Gọi một trong các phương thức signIn(with...:)- như cách bạn thường làm nếu không sử dụng sử dụng MFA (ví dụ: signIn(withEmail:password:)). Nếu phương thức gửi đã xảy ra lỗi với mã secondFactorRequired, hãy bắt đầu quy trình MFA của ứng dụng.

    do {
        let authResult = try await Auth.auth().signIn(withEmail: email, password: password)
    
        // If the user is not enrolled with a second factor and provided valid
        // credentials, sign-in succeeds.
    
        // (If your app requires MFA, this could be considered an error
        // condition, which you would resolve by forcing the user to enroll a
        // second factor.)
    
        // ...
    } catch let error as AuthErrorCode where error.code == .secondFactorRequired {
        // Initiate your second factor sign-in flow. (See next step.)
        // ...
    } catch {
        // Other auth error.
        throw error
    }
    
  2. Trước tiên, quy trình MFA của ứng dụng phải nhắc người dùng chọn yếu tố thứ hai mà họ muốn sử dụng. Bạn có thể xem danh sách các yếu tố thứ hai được hỗ trợ bằng cách kiểm tra thuộc tính hints của một thực thể MultiFactorResolver:

    let mfaKey = AuthErrorUserInfoMultiFactorResolverKey
    guard let resolver = error.userInfo[mfaKey] as? MultiFactorResolver else { return }
    let enrolledFactors = resolver.hints.map(\.displayName)
    
  3. Nếu người dùng chọn sử dụng TOTP, hãy nhắc họ nhập TOTP được hiển thị trên ứng dụng xác thực của họ và sử dụng ứng dụng đó để đăng nhập:

    let multiFactorInfo = resolver.hints[selectedIndex]
    switch multiFactorInfo.factorID {
    case TOTPMultiFactorID:
        let otpFromAuthenticator = // OTP typed by the user.
        let assertion = TOTPMultiFactorGenerator.assertionForSignIn(
            withEnrollmentID: multiFactorInfo.uid,
            oneTimePassword: otpFromAuthenticator)
        do {
            let authResult = try await resolver.resolveSignIn(with: assertion)
        } catch {
            // Wrong or expired OTP. Re-prompt the user.
        }
    default:
        return
    }
    

Huỷ đăng ký TOTP MFA

Phần này mô tả cách xử lý việc người dùng huỷ đăng ký TOTP MFA.

Nếu người dùng đã đăng ký nhiều tùy chọn MFA và nếu họ hủy đăng ký từ tuỳ chọn được bật gần đây nhất, họ sẽ nhận được một auth/user-token-expired và đã đăng xuất. Người dùng phải đăng nhập lại và xác minh thông tin đăng nhập hiện có, chẳng hạn như địa chỉ email và mật khẩu.

Để huỷ đăng ký người dùng, xử lý lỗi và kích hoạt xác thực lại, hãy sử dụng mã sau:

guard let currentUser = Auth.auth().currentUser else { return }

// Prompt the user to select a factor to unenroll, from this array:
currentUser.multiFactor.enrolledFactors

// ...

// Unenroll the second factor.
let multiFactorInfo = currentUser.multiFactor.enrolledFactors[selectedIndex]
do {
    try await currentUser.multiFactor.unenroll(with: multiFactorInfo)
} catch let error as AuthErrorCode where error.code == .invalidUserToken {
    // Second factor unenrolled, but the user was signed out. Re-authenticate
    // them.
}

Bước tiếp theo