iOS指纹识别

指纹登陆

随着智能时代的来临,人们越来越习惯于将重要信息和个人隐私存放于智能手机中。这时手机数据的安全性就变得尤其重要。通常我们使用口令或密码来保护设备,但是随着iPhone和Android手机硬件的逐步升级与支持,使用指纹验证成为了代替密码的一种常规方法。

指纹验证是指通过手机中的触摸传感器来识别用户。通过这种技术我们可以使用指纹解锁设备或在应用中通过指纹授权使用例如指纹登录或指纹支付等功能。

为什么使用指纹验证

对于应用而言,使用指纹验证可以从多方面提升用户体验:

指纹验证是一种更加快捷方便的方法来验证用户身份。传统校验用户身份的方法,通常是使用密码或口令,要想越安全就需要使用越复杂的密码。相较于输入冗长且复杂的密码,指纹识别仅仅需要的是使用指尖触碰传感器完成验证。这无疑能给用户带来更加顺畅的使用体验。

指纹不会被遗忘。如上一条所说,通常密码都是冗长且复杂的,尤其是不常使用的密码,很容易在一段时间后被用户忘记。而使用指纹识别则完全没有这种烦恼,你可以随时使用指纹验证。

指纹验证无需找回功能。由于指纹永远不会被遗忘,也不会改变。通常密码找回的功能对于指纹验证来说就毫无意义。

指纹验证更加安全。通常为了方便记忆密码,用户倾向于使用方便记忆的信息(比如生日)来生成密码,这让密码变得很容易被破解。而即便使用了较为复杂的密码,也无法保证其拥有和指纹一样的独特性和安全性。一旦密码被泄露或盗取,其他人能轻易获取到用户信息。

iOS技术背景

Touch ID

iOS设备下的指纹识别是通过iOS设备提供的Touch ID实现。

Touch ID技术包括在iOS设备上的一套先进的硬件与软件系统:

  • 在iOS硬件设备上的HOME按键由蓝宝石水晶制成,能作为透镜获取到你手指皮肤下纹理的高清图片

  • Touch ID会通过你传入的一系列指纹图片,通过算法生成出属于指纹的数字标识,存储于特殊的芯片上

Touch ID只会存储通过指纹图片生成的数字标识,所以不用担心你真实的指纹泄露。由于指纹的独特性,Touch ID算出的数字标识能相同的概率是50000之1,就是50000个不同指纹才可能会有一对可以通过Touch ID相互匹配。所以Touch ID是一项足够安全的技术。

Touch ID已经备苹果普遍使用于iTunes Store, App Store和Apple Pay。微信和支付宝的支付也已经使用了Touch ID。所以Touch ID也是一项被广泛信赖并使用的技术。

Secure Enclave

如在介绍Touch ID时介绍的一样,Touch ID不会存储任何关于指纹的图片,而是存储的指纹标识。不过即使是这些数字标识也被iOS存储于一块叫做Secure Enclave(安全领域)的芯片上。你的指纹信息只会被用于比对是否与设备中存储的指纹信息进行比对,不能被操作系统,更不会被其他应用访问。这些信息也不会上传到苹果的服务或者被iCloud等云服务备份,不可能被用于与其他的指纹库进行比对。

LocalAuthentication

LocalAuthentication framework是我们的app来使用iOS设备上生物信息验证(Touch ID或者Touch ID)的机制。上文已经介绍过,为了最大限度的保护用户信息的私密性和安全性,iOS上使用了Secure Enclave的方式来将验证数据与设备上的其他系统隔离。用户的认证信息甚至无法被操作系统访问,我们通过认证得到的只是一条布尔值的结果。

Keychain

当需要存储私密信息时,你可以使用Keychain。Keychain是由iOS的Security framework提供的服务,你可以设置keychain中元素的访问权限为每次去读取这项数据时都需要用户的认证(通过Face ID或者Touch ID)。当每次去请求keychian中数据访问权限时,LocalAuthentiation Framework会通过系统展示相应的界面提示用户录入数据,然后将这些数据传入Secure Enclave进行比对。比对结束后,Secure Enclave会成功或失败的结果返回。其间用户或者操作系统都不会也不能获取到用户的指纹信息。

image.png

概述

在iOS和Android技术背景中我们得知:

我们通过指纹识别能获取到只是指纹是否匹配,并不能得到其他与指纹信息有关的结果

但是我们可以存储私密信息,并通过指纹获取访问权限

在此基础上,初步设计了指纹识别的流程。iOS和安卓在指纹识别上的流程由于API的限制不尽相同,但是大概的步骤基本一致:

1.打开指纹认证界面获取获取权限

2.如果步骤1指纹认证成功,获取到权限后尝试从设备中获取用户登录所需密钥

3.如果步骤2成功获取到用户密钥,即用户已经绑定了指纹登陆,那么获取用户密钥登陆

4.如果步骤2未能获取到用户密钥,即用户还未绑定指纹登陆,那么开始绑定指纹的流程

5.绑定指纹的流程可以分为前端和后端的工作,先由后端生成用户登陆所需的独特密钥传回给前端

6.前端收到密钥后将密钥存储于本地设备中

7.使用获取到的密钥就能成功登陆

简化流程如图:

image.png

iOS实现方案

iOS上的指纹登陆方案的主题内容为:

  • 使用Security framework将用户密钥信息存储于keychain中

  • 使用LocalAuthentication framework来验证用户指纹信息,并且获取到keychain中的密钥访问权限

配置工程

要使用Touch ID和Keychain的功能,首先需要将需要的framework添加到工程中。打开工程后选择对应的Target后点击Build Phases > Link Binary With Libraries,点击+号添加LocalAuthentication和Security两个framework。

image.png

TouchID API使用

1.添加头文件

#import <LocalAuthentication/LocalAuthentication.h>

2.判断系统版本

 //首先判断版本
if (NSFoundationVersionNumber < NSFoundationVersionNumber_iOS_8_0) {
      NSLog(@"系统版本不支持TouchID");
      return;
}

3.LAPolicy

在这里简单介绍一下LAPolicy,它是一个枚举.我们根据自己的需要选择LAPolicy,它提供两个值:
LAPolicyDeviceOwnerAuthenticationWithBiometricsLAPolicyDeviceOwnerAuthentication.
<1>. LAPolicyDeviceOwnerAuthenticationWithBiometrics是支持iOS8以上系统,使用该设备的TouchID进行验证,当输入TouchID验证5次失败后,TouchID被锁定,只能通过锁屏后解锁设备时输入正确的解锁密码来解锁TouchID。
<2>.LAPolicyDeviceOwnerAuthentication是支持iOS9以上系统,使用该设备的TouchID或设备密码进行验证,当输入TouchID验证5次失败后,TouchID被锁定,会触发设备密码页面进行验证。

4. canEvaluatePolicy

使用canEvaluatePolicy方法判断设备是否支持TouchID,返回BOOLYES,该设备支持TouchID。

 if ([context canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics error:&error]) {

error为返回验证错误码.具体不解释了.

4. evaluatedPolicyDomainState

context.evaluatedPolicyDomainState用于判断设备上的指纹是否被更改,在LAContext被创建的时候,evaluatedPolicyDomainState才生效,可在TouchID验证成功时,将它记录下来,用于下次使用TouchID时校验,提高安全性。

5. evaluatePolicy

evaluatePolicy方法是对TouchID进行验证,Block回调中如果success为YES则验证成功,为NO验证失败,并对error进行解析.

- (IBAction)loginButtonClick:(UIButton *)sender {

    //首先判断版本
    if (NSFoundationVersionNumber < NSFoundationVersionNumber_iOS_8_0) {
        NSLog(@"系统版本不支持TouchID");
        return;
    }

    LAContext *context = [[LAContext alloc] init];
    context.localizedFallbackTitle = @"输入密码";
    if (@available(iOS 10.0, *)) {
//        context.localizedCancelTitle = @"22222";
    } else {
        // Fallback on earlier versions
    }
    NSError *error = nil;

    if ([context canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics error:&error]) {

        [context evaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics localizedReason:@"通过Home键验证已有手机指纹" reply:^(BOOL success, NSError * _Nullable error) {

            if (success) {
                dispatch_async(dispatch_get_main_queue(), ^{
                    NSLog(@"TouchID 验证成功");
                });
            }else if(error){

                switch (error.code) {
                    case LAErrorAuthenticationFailed:{
                        dispatch_async(dispatch_get_main_queue(), ^{
                            NSLog(@"TouchID 验证失败");
                        });
                        break;
                    }
                    case LAErrorUserCancel:{
                        dispatch_async(dispatch_get_main_queue(), ^{
                            NSLog(@"TouchID 被用户手动取消");
                        });
                    }
                        break;
                    case LAErrorUserFallback:{
                        dispatch_async(dispatch_get_main_queue(), ^{
                            NSLog(@"用户不使用TouchID,选择手动输入密码");
                        });
                    }
                        break;
                    case LAErrorSystemCancel:{
                        dispatch_async(dispatch_get_main_queue(), ^{
                            NSLog(@"TouchID 被系统取消 (如遇到来电,锁屏,按了Home键等)");
                        });
                    }
                        break;
                    case LAErrorPasscodeNotSet:{
                        dispatch_async(dispatch_get_main_queue(), ^{
                            NSLog(@"TouchID 无法启动,因为用户没有设置密码");
                        });
                    }
                        break;
                    case LAErrorTouchIDNotEnrolled:{
                        dispatch_async(dispatch_get_main_queue(), ^{
                            NSLog(@"TouchID 无法启动,因为用户没有设置TouchID");
                        });
                    }
                        break;
                    case LAErrorTouchIDNotAvailable:{
                        dispatch_async(dispatch_get_main_queue(), ^{
                            NSLog(@"TouchID 无效");
                        });
                    }
                        break;
                    case LAErrorTouchIDLockout:{
                        dispatch_async(dispatch_get_main_queue(), ^{
                            NSLog(@"TouchID 被锁定(连续多次验证TouchID失败,系统需要用户手动输入密码)");
                        });
                    }
                        break;
                    case LAErrorAppCancel:{
                        dispatch_async(dispatch_get_main_queue(), ^{
                            NSLog(@"当前软件被挂起并取消了授权 (如App进入了后台等)");
                        });
                    }
                        break;
                    case LAErrorInvalidContext:{
                        dispatch_async(dispatch_get_main_queue(), ^{
                            NSLog(@"当前软件被挂起并取消了授权 (LAContext对象无效)");
                        });
                    }
                        break;
                    default:
                        break;
                }
            }
        }];

    }else{
        NSLog(@"当前设备不支持TouchID");
    }
}

上面这个代码, 是整个TouchID的核心,也几乎是所有代码了.

验证

验证必须使用真机

image
image

总结:TouchID使用起来不难,重要的是使用流程逻辑.

以登录为例,一般来说流程是这样的:
1.开启指纹登录:首次登陆使用密码登录,登录后,可以设置一个开启指纹ID登录的按钮,来进行指纹认证.
2.验证:检测是否支持TouchID.
3.生成设备账号/密码:TouchID验证通过后,根据当前已登录的账号和硬件设备Token,生成设备账号/密码(规则可自定,密码要长要复杂),并保存在keychain;
4.绑定:生成设备账号/密码后,将原账号及设备账号/密码,加密后(题主使用的是RSA加密)发送到服务端进行绑定;
5.成功:验证原账号及设备账号有效后,返回相应状态,绑定成功则完成整个TouchID(设备)绑定流程。

注意的坑

在ios10指纹验证错误过多会报错,然后不会弹出系统密码输入界面:

打印error.code,是:-8
打印error.localizedDescription,是:Biometry is locked out
上网查到ios9以前会弹出系统密码输入界面。

ios10及以后呢?

ios9以前这样写:

//是否支持touchid
[_context canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics error:&error]
//验证指纹是否匹配
[_context evaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics localizedReason:@"通过home键验证已有指纹" reply:^(BOOL success, NSError * _Nullable error) {}

IOS10上只需把上面两个地方的 LAPolicyDeviceOwnerAuthenticationWithBiometrics
换成
LAPolicyDeviceOwnerAuthentication
即可。

ios10这样写

//是否支持touchid
[_context canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics error:&error]
//报错码为-8时,调用此方法会弹出系统密码输入界面

[_context evaluatePolicy:LAPolicyDeviceOwnerAuthentication localizedReason:@"指纹验证错误次数过多,请输入密码" reply:^(BOOL success, NSError * _Nullable error){

当然为了适配ios8,9,10可以在适当的时候,做适当的操作。

参考链接:
iOS指纹登陆
iOS 指纹登录(TouchID)集成方案
IOS TouchId开发 Biometry is locked out
iOS指纹识别登录流程及实现

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,185评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,445评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,684评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,564评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,681评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,874评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,025评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,761评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,217评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,545评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,694评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,351评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,988评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,778评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,007评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,427评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,580评论 2 349