iOS) Face ID & Touch ID - Biometrics Authentication(생체인식 인증)

5 minute read

😨 Face ID 를 활용한 오싹한 생체인식 인증 실험

시작 전

😃 Local Authentication

Authenticate users biometrically(생체인식) 또는 이미 알고 있는 passphrase(암호)로 사용자를 인증합니다.

Overview

많은 사용자가 TouchID 또는 FaceID 와 같은 생체인식에 의존해서 장비에 손쉽게 접근할 수 있다. 대체 옵션으로 생체 인식이 없는 경우 암호가 비슷한 용도로 활용된다. LocalAuthentication 프레임워크를 사용하여 앱에서 이러한 메커니즘을 활용하고 이미 구현한 인증 절차를 확장할 수 있다.

보안을 극대화하기 위해서 underlying authentication data(기본 인증 데이터)에 접근할 수 없다. 예를들어 지문 이미지에 접근할 수 없다는 뜻이다. 시스템의 나머지 부분과 격리된 하드웨어 기반 보안 프로세서인 Secure Enclave는 이 데이터를 운영 체제의 손마저 닿지 않는 곳에 관리합니다.

대신 특정 policy 를 지정하고 사용자에게 인증을 원하는 이유를 알려주는 메시징을 제공합니다. 그런 다음 Secure Enclave 와 조정하여 작업을 수행한다. 이후에는 성공과 실패를 나타내는 Boolean 결과만 얻는다.

😃 이제 애플에서 제공하는 예제코드에 대해서 알아보자

Apple Developer Documentation

Overview

사용자는 Touch ID 와 Face ID 와 같은 인증 매커니즘을 통해서 장치에 쉽게 접근할 수 있기 때문에 좋아한다. LocalAuthentication 프레임워크를 채택하면 일반적인 경우 사용자 인경 경험을 간소화하는 동시에 생체인식을 사용할 수 없을 때를 대비한 대체 옵션도 제공한다.

Set the Face ID Usage Description

biometrics 를 사용하는 모든 프로젝트에서 Info.plist 파일에 NSFaceIDUsageDescription 키를 가진다. 이 키가 없으면 시스템은 앱이 Face ID 를 사용을 허락하지 않는다. 키의 값은 사용자가 처음으로 Face ID 를 사용할 때 시스템이 보여주는 문자열이다. 문자열은 앱이 이 인증 매커니즘을 액세스해야 하는 이유를 명확하게 설명해준다. 시스템은 Touch ID 에 대한 유사한 사용 설명을 필요로 하지 않는다.

(key 로 Privacy - Face ID Usage Description 를 사용해도 가능하다. 어차피 위의 키값을 입력하면 변환된다.)

Create and Configure a Context

앱에서 LAContext 인스턴스를 사용해서 생체인식 인증을 사용할 수 있다. (LAContext 는 Secure Enclave 와 앱과의 상호작용을 중개한다.) context 를 생성하며 시작한다 :

var context = LAContext()

context 에서 사용하는 메시징을 커스텀해서 유저를 흐름으로 안내할 수 있다. 예를 들어, 다양한 alert view 에 나타나는 Cancel button 에 대한 커스텀 메시지를 설정할 수 있다.

context.localizedCancelTitle = "Enter Username/Password"

이것은 사용자가 버튼을 탭하면 일반 인증 절차로 되돌아갈 것을 이해하는데 도움이 된다.

Test Policy Availability

인증을 시도하기 전에 canEvaluatePolicy(_:error:) 메서드를 호출해서 인증할 수 있는지 테스트할 수 있다.

var error: NSError?
if context.canEvaluatePolicy(.deviceOwnerAuthentication, error: &error) {

테스트 할 LAPolicy 열거에서 값을 선택한다. poicy 는 인증이 작동하는 방식을 제어한다. 예를 들어, 위의 코드에서 사용된 LAPolicy.deviceOwnerAuthentication 은 생채인식이 실패하거나 사용할 수 없는 경우 passcode 로 되돌릴 수 있다. 또는 passcode 로 돌릴 수 없는 LAPolicy.deviceOwnerAuthenticationWithBiometrics 로 지정할 수도 있다.

Evaluate a Policy

인증할 준비가 되면 이미 테스트한 policy 와 동일한 policy 를 사용해서 evaluatePolicy(_:localizedReason:reply:) 를 호출한다.

let reason = "Log in to your account"
context.evaluatePolicy(.deviceOwnerAuthentication, localizedReason: reason ) { success, error in

    if success {

        // Move to the main thread because a state update triggers UI changes.
        DispatchQueue.main.async { [unowned self] in
            self.state = .loggedin
        }

    } else {
        print(error?.localizedDescription ?? "Failed to authenticate")

        // Fall back to a asking for username and password.
        // ...
    }
}

Touch ID 의 경우 또는 사용자가 passcode 를 입력하면 시스템은 위의 메소드에서 제공하는 reason 을 인증 이유로 표시한다.

(다음과 같이 “Log in to your account” 문자열이 passcode 사용 시 인증 이유로 표시된다.)

앱이 사용자에게 인증을 요청하는 이유에 대해서 운영하는 모든 지역에 localized 된 명확한 설명을 제공하는 것은 중요하다. 앱 이름은 위의 사진처럼 이유 앞에 이미 나타나므로 메시지에 포함시킬 필요가 없다.

Optionally, Adjust Your User Interface to Accommodate Face ID

생체 인식 스캔 작업을 제외하고 Face ID 는 Touch ID 와 중요한 차이점을 보여준다.

  • 앱이 Touch ID 를 사용하려고 하면 손가락을 제시하라는 시스템 메시지가 표시된다. 사용자는 프롬프트를 취소하여 작업에 대해 생각하고 취소할 시간이 있다. Face ID 를 호출할때는 기기가 바로 사용자의 얼굴을 스캔하기 시작한다. 사용자는 취소할 수 있는 마지막 기회를 얻지 못한다.

이러한 동작 차이를 수용하기 위해서 생체 인식 종류에 따라 다른 UI 를 제공할 수 있다.

아래와 같은 애플 샘플 앱의 경우 버튼을 탭하면 즉각적인 Face ID 스캔이 발생하는 것을 경고메시지 텍스트 라벨을 포함하여 다른 UI 로 제공한다.

context 의 biometryTpe 파라미터를 읽어서 장치가 어떤 biometry 를 지원하는지 테스트할 수 있다.

(다음의 코드는 Face ID 를 지원하는 않는 디바이스의 경우 혹은 이미 로그인된 경우 Face ID 인증 라벨을 hidden 시키는 코드이다.)

faceIDLabel.isHidden = (state == .loggedin) || (context.biometryType != .faceID)

(다음은 Face ID 를 지원하지 않는 iPhone SE 2세대이다. 실행했을 경우에 라벨이 hidden 된 것을 볼 수 있다.)

Provide a Fallback Alternative to Biometrics

다양한 이유로 인증은 실패하거나 사용할 수 없는 경우가 있다.

  • The user’s device doesn’t have Touch ID or Face ID.
  • The user isn’t enrolled in biometrics, or doesn’t have a passcode set.
  • The user cancels the operation.
  • Touch ID or Face ID fails to recognize the user.
  • You’ve previously invalidated the context with a call to the invalidate() method.(invalidate() 메서드를 호출해서 context 를 무효화하는 것을 말한다. )

가능한 error 조건의 전체 목록은 LAError.Code 를 참조하자.

샘플 앱은 대체 인증을 구현하지 않았다. 실제 앱에서는 local authentication error 가 발생하면 사용자 이름과 비밀번호를 묻는 것과 같은 고유한 인증 체계로 대체한다. (즉, 유일한 인증옵션으로 대하지 말라는 것.)

이미 하는 일에 보완책으로 biometrics 를 제공해라. 유일한 인증 옵션으로 biometrics 를 의존하지 마라.

😃 LAError

LocalAuthentication 프레임워크에서 발생한 오류.

😃 LAError.Codes

policy 평가에 실패했을 때 LocalAuthentication 프레임워크가 반환하는 Error codes 이다.

내용을 보면 Biometry Failure 에 해당하는 에러코드가 있다.

시작하기

아이폰 기기가 Face ID 를 지원해야하고 Face ID 를 사용하고 있는 상황에서 가능하다.

😃 프로젝트 설정

  • Info.plist 파일

  • Face ID 사용
import UIKit
import LocalAuthentication

class ViewController: UIViewController {
    
    enum AuthenticationState {
        case loggedin, loggedout
    }
    
    // ✅ 현재 로그인 상태에 따른 UI 변화
    var state = AuthenticationState.loggedout {
        didSet {
            if state == .loggedin {
                loginButton.setTitle("Logout", for: .normal)
            } else {
                loginButton.setTitle("Login", for: .normal)
            }
        }
    }
    
    @IBOutlet weak var loginButton: UIButton!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        loginButton.setTitle("Login", for: .normal)
    }
    
    @IBAction func touchLoginButton(_ sender: Any) {
        if state == .loggedin {
            
            state = .loggedout
        
        } else {
            // ✅ LAContext 로 Secure Enclave 와 앱과의 상호작용을 중개.
            let context = LAContext()
            
            // ✅ alert view 에서 cancel button 메시지.
            context.localizedCancelTitle = "Enter Username/Password"
            
            var error: NSError?
            
            // ✅ 지정한 policy 로 biometrics 인증이 가능한지 테스트.
            if context.canEvaluatePolicy(.deviceOwnerAuthentication, error: &error) {
                
                let reason = "Log in to your account"
                
                // ✅ 지정한 policy 로 biometrics 인증 시작.
                context.evaluatePolicy(.deviceOwnerAuthentication, localizedReason: reason ) { success, error in
                    if success {
                        // ✅ state 업데이트는 UI 변화를 일으켜서 main thread 에서 처리해야한다.
                        DispatchQueue.main.async { [unowned self] in
                            self.state = .loggedin
                            print("state : \(self.state)")
                        }
                    } else {
                        print(error?.localizedDescription ?? "Failed to authenticate")
                        
                        // Fall back to a asking for username and password.
                        // ...
                    }
                }
            }
        }
    }
}

시뮬레이터에서 Face ID 실행해보기

  • Features → Face ID → Enrolled 로 활성화해준다.
  • (활성화 이전에 생체인식 인증을 시도하면 passcode 를 입력받으려 한다.)

  • Face ID 를 매칭 / 비매칭 선택할 수 있다.

결과

출처

Apple Developer Documentation

Categories:

Updated: