11

我正在研究 Apple 的 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-Password。这是正常的行为,因为电话可能已被知道密码并添加自己的指纹以购买昂贵东西的其他人拿走。

我的问题:我能否检测到自上次使用本地身份验证器后是否添加了新指纹?

4

6 回答 6

20

现在这在 iOS9 中是可能的。已将属性评估策略域状态添加到 LAContext。

如果指纹数据库被修改(指纹被添加或移除),由评估策略域状态返回的数据将会改变。更改的性质无法确定,但通过在不同的 evaluatePolicy 调用后比较评估的PolicyDomainState 的数据,您可以检测到指纹集已被修改。

请注意,仅当调用 evaluatePolicy 并执行成功的 Touch ID 身份验证时,或者当 canEvaluatePolicy 对生物识别策略成功时,才会设置此属性。

于 2015-08-13T04:49:56.057 回答
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

于 2016-07-15T15:20:54.210 回答
5

简而言之; 不。

更详细一点;该LocalAuthentication框架是一个严密保护的黑匣子。您从中获得的信息非常有限。你与它的交互是这样的:

  • 询问它是否能够针对某种类型的策略进行身份验证(在撰写本文时只有 1 个可用 - 生物识别(Touch ID))
  • 如果可以,请它实际执行
  • 系统接管实际身份验证
  • 它让您知道身份验证是否成功(如果没有,它会告诉您原因)

您不知道实际的身份验证过程(例如,使用了哪个手指)。当然,这是设计使然。Apple 不想也不需要让您访问此类信息。

于 2014-10-22T09:07:31.273 回答
3

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

斯威夫特 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];
    }];
}
于 2017-01-26T18:36:53.407 回答
3

我建议将评估的PolicyDomainState值存储到钥匙串中,而不是将其存储在NSUserDefault中。

您可以将evaluatePolicyDomainState的数据值转换为字符串,即44 个字符的字符串。下面是将评估的PolicyDomainState数据值转换为字符串的代码 -

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;那么这个数据值将被更改,您可以根据您的项目需要采取必要的步骤来处理更改。

于 2018-01-29T17:13:54.820 回答
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

于 2018-01-26T10:46:37.867 回答