iOS8 TouchID检测是否添加了指纹

11

我正在研究苹果的Touch ID,更确切地说是本地认证器。 目前的文档非常匮乏,主要只有这个:

LAContext *myContext = [[LAContext alloc] init];
NSError *authError = nil;
NSString *myLocalizedReasonString = <#String explaining why app needs authentication#>;

if ([myContext canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics    error:&authError]) {
[myContext evaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics
              localizedReason:myLocalizedReasonString
                        reply:^(BOOL success, NSError *error) {
        if (success) {
            // User authenticated successfully, take appropriate action
        } else {
            // User did not authenticate successfully, look at error and take appropriate action
        }
    }];
} else {
// Could not evaluate policy; look at authError and present an appropriate message to user
}

源自https://developer.apple.com/documentation/localauthentication

使用指纹进行身份验证的想法很不错。但是如果我知道密码,我可以在设备上添加指纹,并且很容易获取密码,例如坐在火车上旁边观察受害者输入密码。

我希望将指纹用作安全验证的一种方式,但同时希望能够检测到自上次请求指纹以来是否已添加了新的指纹。

Apple 在 AppStore 中就是这样做的。如果您想在 AppStore 上验证交易并在上次交易后添加了新的指纹,则 AppStore 会要求您提供 AppleId 密码。这是明智的行为,因为手机可能已被他人拿走,他们知道密码并添加了自己的指纹购买昂贵的物品。

我的问题:我可以检测到自上次使用本地认证器以来是否已添加新指纹吗?

6个回答

20

iOS9 现在可以实现这个功能。属性 evaluatedPolicyDomainState 被添加到了 LAContext 中。

如果指纹数据库被修改(添加或删除了指纹),那么 evaluatedPolicyDomainState 返回的数据将会发生变化。虽然无法确定变化的具体特征,但通过比较不同 evaluatePolicy 调用后 evaluatedPolicyDomainState 的数据,可以检测出指纹集合是否被修改过。

请注意,只有在进行 Touch ID 认证成功后调用 evaluatePolicy(或针对生物识别策略调用 canEvaluatePolicy)时,才会设置此属性。


我在我的应用程序中集成了Touch ID。我想将Touch ID用作第二个安全认证。我想检测是否添加或删除了新的指纹。你能帮我编写程序吗? - Begum
1
你最好使用TouchID来解锁钥匙串中的令牌,而不是使用本地身份验证。如果您使用策略kSecAccessControlTouchIDCurrentSet,则如果指纹集合发生更改,则该令牌将变得无法访问。请参见https://dev59.com/sV4c5IYBdhLWcg3wSIgs#29910710。 - Keith Coughtrey

11

正如 Keith 所说,在 iOS 9 中是可能的。您应该这样做。

    let context = LAContext()
    context.canEvaluatePolicy(.DeviceOwnerAuthenticationWithBiometrics, error: nil)

    if let domainState = context.evaluatedPolicyDomainState
        where domainState == oldDomainState  {
        // Enrollment state the same

    } else {
        // Enrollment state changed

    }
每次您添加或删除指纹时,域状态都会发生变化。您需要调用canEvaluatePolicy来更新evaluatedPolicyDomainState

请注意,您也可以调用“evaluatePolicy”来获取最新的evaluatedPolicyDomainState。 - Rashmi Ranjan mallick

5
简而言之,不行。
稍微详细一点,LocalAuthentication框架是一个严密保护的黑匣子。你从中得到的信息非常有限。你与它的交互大致如下:
  • 询问它是否能够认证某种类型的策略(目前仅有1种可用 - 生物识别(Touch ID))
  • 如果可以,请求它实际执行认证
  • 系统接管实际认证过程
  • 它告诉你认证是否成功(如果不成功,它会告诉你原因)
你无法了解实际的认证过程(例如使用哪个手指)。当然,这是有意设计的。苹果不希望也不需要向你提供这样的信息。

1
希望未来能够开放这个界面更多。如果我不知道是否有人搞乱了TouchID设置,那么它就没有什么用处了。 - Stas Stelle
我明白你的意思,但是这个想法是让你不必担心认证的细节;你可以让系统为你处理它。 - JoeFryer
1
这并不是经过深思熟虑的,要添加一个新的指纹,我需要输入每10分钟在公交车、火车、人行道上人们可以看到的同样代码。如果有人想要使用Touch ID进行更多的测试,很容易窃取该设备,输入新的指纹并滥用新授权的身份验证。这样比静态短密码还不安全。 - Stas Stelle
但是这个想法是,大部分时间你不需要输入密码来解锁设备,而是使用Touch ID,这样人们就不太可能看到你输入密码了。 - JoeFryer
它将取决于人们如何使用它。 - Stas Stelle

3
我建议将评估的 evaluatedPolicyDomainState 值存储到钥匙串中,而不是存储在 NSUserDefault 中。
您可以将 evaluatedPolicyDomainState 的数据值转换为字符串,这是一个44个字符长的字符串。以下是将 evaluatedPolicyDomainState 数据值转换为字符串的代码 -

if context.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: nil) {
    if let domainState = context.evaluatedPolicyDomainState {
        let bData = domainState.base64EncodedData()
        if let decodedString = String(data: bData, encoding: .utf8) {
            print("Decoded Value: \(decodedString)")
        }
    }
}

现在,如果设备所有者更改了Touch ID,例如添加了新的指纹ID,则此数据值将发生更改,您可以根据项目需求采取必要的步骤来处理更改。

3

这是验证指纹是否添加或删除的解决方案,Swift和ObjC解决方案之间的区别在于canEvaluatePolicy仅验证是否有更改,而evaluatePolicy则打开模态验证。

Swift 5.2

    let context = LAContext()
    context.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: nil)

    let defaults = UserDefaults.standard
    let oldDomainState = defaults.object(forKey: "domainTouchID") as? Data

    if let domainState = context.evaluatedPolicyDomainState, domainState == oldDomainState  {
        // Enrollment state the same
        print("nothing change")

    } else {
        // Enrollment state changed
        print("domain state was changed")
    }

    // save the domain state for the next time
    defaults.set(context.evaluatedPolicyDomainState, forKey: "domainTouchID")

Objective-C

    - (void)evaluatedPolicyDomainState {
    LAContext *context = [[LAContext alloc] init];
    __block  NSString *message;

    // show the authentication UI with reason string
    [context evaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics localizedReason:@"Unlock access to locked feature" reply:^(BOOL success, NSError *authenticationError) {

        if (success) {
        
            // load the last domain state from touch id
            NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
        
            NSData *oldDomainState = [defaults objectForKey:@"domainTouchID"];
        
            NSData *domainState = [context evaluatedPolicyDomainState];

            // check for domain state changes
            if ([oldDomainState isEqual:domainState]) {             
                message = @"nothing change";
            } else {
                message = @"domain state was changed";
            }
        
            // save the domain state that will be loaded next time
            oldDomainState = [context evaluatedPolicyDomainState];
            [defaults setObject:oldDomainState forKey:@"domainTouchID"];
            [defaults synchronize];
        
        } else {
            message = [NSString stringWithFormat:@"evaluatePolicy: %@", authenticationError.localizedDescription];
        }
    
        [self printMessage:message inTextView:self.textView];
    }];
}

0

我想要添加一些内容,

-(BOOL)hasFingerPrintChanged
{
   BOOL changed = NO;

   LAContext *context = [[LAContext alloc] init];
   [context canEvaluatePolicy:LAPolicyDeviceOwnerAuthentication error:nil];

   NSData *domainState = [context evaluatedPolicyDomainState];

   // load the last domain state from touch id
   NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
   NSData *oldDomainState = [defaults objectForKey:@"domainTouchID"];

        if (oldDomainState)
        {
            // check for domain state changes

            if ([oldDomainState isEqual:domainState])
            {
                NSLog(@"nothing changed.");
            }
            else
            {
                changed = YES;
                NSLog(@"domain state was changed!");

                NSString *message = @"Your Touch ID is invalidated, because you have added or removed finger(s).";

            }

        }

        // save the domain state that will be loaded next time
    [defaults setObject:domainState forKey:@"domainTouchID"];
    [defaults synchronize];


        return changed;
    }

最好将用户密码等信息存储在钥匙串中。 我正在使用https://github.com/reidmain/FDKeychain


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接