เพิ่มการตรวจสอบสิทธิ์แบบหลายปัจจัยของ TOTP ในแอป iOS

หากอัปเกรดเป็นการตรวจสอบสิทธิ์ Firebase ด้วย Identity Platform แล้ว คุณจะเพิ่มการตรวจสอบสิทธิ์แบบหลายปัจจัย (TOTP) แบบหลายปัจจัย (MFA) แบบอิงตามเวลาลงในแอปได้

การตรวจสอบสิทธิ์ Firebase ด้วย Identity Platform ช่วยให้คุณใช้ TOTP เป็นปัจจัยเสริมสำหรับ MFA ได้ เมื่อคุณเปิดใช้ฟีเจอร์นี้ ผู้ใช้ที่พยายามลงชื่อเข้าใช้แอปของคุณจะเห็นคำขอใช้ TOTP โดยต้องใช้แอป Authenticator ที่สร้างรหัส TOTP ที่ถูกต้องได้ เช่น Google Authenticator

ก่อนเริ่มต้น

  1. เปิดใช้ผู้ให้บริการอย่างน้อย 1 รายที่รองรับ MFA โปรดทราบว่าผู้ให้บริการทั้งหมด ยกเว้นการสนับสนุน MFA ต่อไปนี้

    • การตรวจสอบสิทธิ์ทางโทรศัพท์
    • การตรวจสอบสิทธิ์แบบไม่ระบุชื่อ
    • โทเค็นการตรวจสอบสิทธิ์ที่กำหนดเอง
    • เกมเซ็นเตอร์ของ Apple
  2. ตรวจสอบว่าแอปยืนยันอีเมลของผู้ใช้ MFA ต้องมีการยืนยันทางอีเมล เพื่อป้องกันไม่ให้ผู้ไม่ประสงค์ดีลงทะเบียนใช้บริการด้วยอีเมลที่ไม่ได้เป็นเจ้าของ และจะล็อกตัวเจ้าของอีเมลไว้ด้วยการเพิ่มปัจจัยที่สอง

  3. ติดตั้ง Firebase Apple SDK หากยังไม่ได้ทำ

    TOTP MFA รองรับเฉพาะใน Apple SDK เวอร์ชัน v10.12.0 ขึ้นไป และใน iOS เท่านั้น

เปิดใช้ TOTP MFA

หากต้องการเปิดใช้ TOTP เป็นปัจจัยที่ 2 ให้ใช้ Admin SDK หรือเรียกใช้ปลายทาง REST ของการกำหนดค่าโปรเจ็กต์

หากต้องการใช้ Admin SDK ให้ทำดังนี้

  1. ติดตั้ง Firebase Admin Node.js SDK หากยังไม่ได้ทำ

    ระบบรองรับ TOTP MFA ใน Firebase Admin Node.js SDK เวอร์ชัน 11.6.0 ขึ้นไปเท่านั้น

  2. เรียกใช้โค้ดต่อไปนี้

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

    แทนที่รายการต่อไปนี้

    • NUM_ADJ_INTERVALS: จำนวนช่วงของกรอบเวลาที่อยู่ติดกันซึ่งระบบจะยอมรับ TOTP ตั้งแต่ 0 ถึง 10 ค่าเริ่มต้นคือ 5

      TOTP ทำงานโดยการตรวจสอบว่าเมื่อฝ่าย 2 ฝ่าย (ผู้ตรวจสอบและโปรแกรมตรวจสอบ) สร้าง OTP ภายในกรอบเวลาเดียวกัน (โดยทั่วไปยาว 30 วินาที) ก็จะสร้างรหัสผ่านเดียวกัน อย่างไรก็ตาม คุณจะกำหนดค่าบริการ TOTP ให้ยอมรับ TOTP จากหน้าต่างที่อยู่ติดกันได้ด้วย เพื่อรองรับการเลื่อนเวลาระหว่างแต่ละฝ่ายและเวลาที่มนุษย์ตอบสนอง

หากต้องการเปิดใช้งาน TOTP MFA โดยใช้ REST API ให้เรียกใช้คำสั่งต่อไปนี้

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"
            }
          }]
       }
    }'

แทนที่รายการต่อไปนี้

  • PROJECT_ID: รหัสโปรเจ็กต์
  • NUM_ADJ_INTERVALS: จำนวนช่วงกรอบเวลา ตั้งแต่ 0 ถึง 10 ค่าเริ่มต้นคือ 5

    TOTP ทำงานโดยการตรวจสอบว่าเมื่อฝ่าย 2 ฝ่าย (ผู้ตรวจสอบและโปรแกรมตรวจสอบ) สร้าง OTP ภายในกรอบเวลาเดียวกัน (โดยทั่วไปยาว 30 วินาที) ก็จะสร้างรหัสผ่านเดียวกัน อย่างไรก็ตาม คุณจะกำหนดค่าบริการ TOTP ให้ยอมรับ TOTP จากหน้าต่างที่อยู่ติดกันได้ด้วย เพื่อรองรับการเลื่อนเวลาระหว่างแต่ละฝ่ายและเวลาที่มนุษย์ตอบสนอง

เลือกรูปแบบการลงทะเบียน

คุณเลือกได้ว่าจะให้แอปต้องใช้การตรวจสอบสิทธิ์แบบหลายปัจจัยหรือไม่ ตลอดจนวิธีและเวลาในการลงทะเบียนผู้ใช้ รูปแบบทั่วไปบางส่วนมีดังนี้

  • ลงทะเบียนปัจจัยที่ 2 ของผู้ใช้เพื่อลงทะเบียน ใช้วิธีนี้หากแอปกำหนดให้มีการตรวจสอบสิทธิ์แบบหลายปัจจัยสำหรับผู้ใช้ทั้งหมด

  • เสนอตัวเลือกที่ 2 แบบข้ามได้เพื่อลงทะเบียนปัจจัยที่ 2 ในระหว่างการลงทะเบียน หากต้องการส่งเสริมการตรวจสอบสิทธิ์แบบหลายปัจจัยในแอป คุณอาจใช้วิธีนี้

  • เพิ่มความสามารถในการเพิ่มปัจจัยที่ 2 จากหน้าการจัดการบัญชีหรือโปรไฟล์ผู้ใช้แทนหน้าจอลงชื่อสมัครใช้ ซึ่งจะช่วยลดความยุ่งยากระหว่างขั้นตอนการลงทะเบียน ในขณะที่ยังให้ผู้ใช้ที่ไวต่อความปลอดภัยใช้การตรวจสอบสิทธิ์แบบหลายปัจจัยได้

  • ต้องเพิ่มปัจจัยที่ 2 เพิ่มเติมเมื่อผู้ใช้ต้องการเข้าถึงฟีเจอร์ต่างๆ ที่มีข้อกําหนดด้านความปลอดภัยเพิ่มขึ้น

ลงทะเบียนผู้ใช้ใน TOTP MFA

หลังจากที่คุณเปิดใช้ TOTP MFA เป็นปัจจัยที่ 2 สำหรับแอปแล้ว ให้ใช้ตรรกะฝั่งไคลเอ็นต์เพื่อลงทะเบียนผู้ใช้ใน TOTP MFA ต่อไปนี้

  1. ตรวจสอบสิทธิ์ผู้ใช้อีกครั้ง

  2. สร้างข้อมูลลับ TOTP สำหรับผู้ใช้ที่ตรวจสอบสิทธิ์แล้ว

    // 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. แสดงข้อมูลลับแก่ผู้ใช้และแจ้งให้ผู้ใช้ป้อนลงในแอป Authenticator ดังนี้

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

    นอกเหนือจากการแสดงคีย์ลับแล้ว คุณยังลองเพิ่มคีย์ลงในแอป Authenticator เริ่มต้นของอุปกรณ์โดยอัตโนมัติได้ด้วย โดยการสร้าง URI ของคีย์ที่ใช้ร่วมกับ Google Authenticator ได้และส่งไปยัง openInOTPApp(withQRCodeURL:):

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

    เมื่อผู้ใช้เพิ่มข้อมูลลับลงในแอป Authenticator ก็จะเริ่มสร้าง TOTP

  4. แจ้งให้ผู้ใช้พิมพ์ TOTP ที่แสดงโดยแอป Authenticator ของตน แล้วใช้คีย์ดังกล่าวเพื่อดำเนินการลงทะเบียน 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.
    }
    

ให้ผู้ใช้ลงชื่อเข้าใช้ด้วยปัจจัยที่ 2

หากต้องการลงชื่อเข้าใช้ให้ผู้ใช้ด้วย TOTP MFA ให้ใช้รหัสต่อไปนี้

  1. เรียกใช้เมธอด signIn(with...:) แบบใดแบบหนึ่งตามที่คุณจะทำหากคุณไม่ได้ใช้ MFA (เช่น signIn(withEmail:password:)) หากเมธอดแสดงข้อผิดพลาดที่มีรหัส secondFactorRequired ให้เริ่มขั้นตอน MFA ของแอป

    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. ขั้นตอน MFA ของแอปควรแจ้งให้ผู้ใช้เลือกปัจจัยที่ 2 ที่ต้องการใช้ก่อน คุณดูรายการปัจจัยที่ 2 ที่รองรับได้โดยการตรวจสอบพร็อพเพอร์ตี้ hints ของอินสแตนซ์ MultiFactorResolver ดังนี้

    let mfaKey = AuthErrorUserInfoMultiFactorResolverKey
    guard let resolver = error.userInfo[mfaKey] as? MultiFactorResolver else { return }
    let enrolledFactors = resolver.hints.map(\.displayName)
    
  3. หากผู้ใช้เลือกใช้ TOTP ให้แจ้งให้ผู้ใช้พิมพ์ TOTP ที่แสดงในแอป Authenticator ดังกล่าวเพื่อลงชื่อเข้าใช้

    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
    }
    

ยกเลิกการลงทะเบียนจาก TOTP MFA

หัวข้อนี้จะอธิบายวิธีจัดการกับผู้ใช้ที่ยกเลิกการลงทะเบียนจาก TOTP MFA

หากผู้ใช้ได้ลงชื่อสมัครใช้ตัวเลือก MFA หลายตัวเลือก และหากผู้ใช้ยกเลิกการลงทะเบียนจากตัวเลือกที่เปิดใช้งานล่าสุด ผู้ใช้จะได้รับ auth/user-token-expired และออกจากระบบ ผู้ใช้ต้องลงชื่อเข้าใช้อีกครั้งและยืนยันข้อมูลเข้าสู่ระบบที่มีอยู่ เช่น อีเมลและรหัสผ่าน

ใช้โค้ดต่อไปนี้เพื่อยกเลิกการลงทะเบียนผู้ใช้ จัดการข้อผิดพลาด และเรียกใช้การตรวจสอบสิทธิ์อีกครั้ง

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.
}

ขั้นตอนถัดไป