钥匙串(keychain)服务编程指南 Ios部分

介绍

钥匙串服务提供了一种安全存储信息的方式,比如:密码,关键字,证书和一个或一些用户的数据. 一个用户只能通过一个密码解锁钥匙串,然后钥匙串会为其对应的应用存储和获取密码.下面会讨论经常被开发者使用的用于存储的数据结构和钥匙串如何为你服务.

如果你需要处理以下的密码相关的问题,你需要这个文档:

苹果的钥匙串和其他的安全APIs都是在建立在开源的 Common Data Security Architecture(CDSA) 和 Common Security Services Manager(CSSM). 更多信息可以看这里

钥匙串服务原理

通常计算机用户需要管理很多的账户和密码来登录不同的网站. 安全FTP服务器(Secure FTP servers), 苹果分享服务(AppleShare servers), 数据库服务(database servers), 安全站点(secure websites),及时通讯账户(instant messaging accounts), 和其他许多服务都需要在用户使用之前进行账号认证.通常用户会写下一个简单,容易记住的密码在在不同的服务中,或者写下很容易找到的密码.这其中任何一种情况都属于一种妥协的安全保障.

钥匙串服务为解决这个问题而提出了方案. 通过简单的调用钥匙串服务接口,应用可以将登录信息存储到钥匙串, 同样的, 也可以从钥匙串去除登录信息. 钥匙串是一个加密的容器, 他为不同的应用和安全服务保存信息. 钥匙串是一个加密容器的意思是当他时被锁住的时候,没有人可以访问其保护的内容. 在OS X系统中, 用户可以锁住钥匙串,通过键入系统密码, 才可以让系统信任的程序访问钥匙串内容. 在 iOS系统中, 每个应用只能访问自己应用的钥匙串内容, 用户永远不能解锁钥匙串, 然而在OS X 系统中, 任何应用可以访问被授予权限范围内的任何钥匙串信息, 在 iOS系统中, 应用程序只能访问自己的钥匙串信息.

注意: 在iPhone上, 钥匙串的访问权限取决于为应用程序签名的provisioning profile. 保证在不同的版本中使用相同的provisioning profile

在用户的角度上,钥匙串是一个透明的认证服务. 这意味着(在 OS X 中解锁了钥匙串), 用户在使用任何一个已经将密码存储到钥匙串中的服务时,不用输入密码. 在 OS X 中用户只要输入一次密码就可以访问需要应用程序, 服务器, 站点等等. 在 iOS 中, 用户甚至不需要输入密码.

下图表示了用户,钥匙串和应用程序之间的关系,在iOS中,需要忽略第一步, 在iOS中用户不能解锁钥匙串.应用程序可以访问自己的钥匙串信息, 但是不能访问其他应用程序创建的信息.

默认情况下,在 OS X 系统中, 每个登录的账号都有一个钥匙串(在 OS X 10.3中 叫 login.keychain), 但是用户或应用程序可以按照意愿去创建多个钥匙串, login keychain默认是锁定的, 当用户输入了正确的密码后, login keychain 自动解锁.当第一次创建钥匙串, login keychain是默认的钥匙串, 默认钥匙串存储着新创建的没有指定钥匙串的内容. 用户也可以改变默认的钥匙串,但是 login keychain 不会改变. 在iOS中, 情况简单的多, 系统只有一个可供所有应用访问的钥匙串, 一个应用程序只能访问它自己的内容(可能只有创建它的应用程序才拥有对内容的之久引用).

在iOS系统中, 钥匙串服务的API提供了所有的可用的方法去操作钥匙串内容.

iPhone的钥匙串备份

在iOS中, 应用程序只能访问自己的钥匙串内容而不能访问其他应用程序的. 系统会对钥匙串生成一个自己的密码. 然后将密码存储到设备上, 允许任何应用程序访问.当用户备份iPhone上的数据的时候,钥匙串也会备份,但是钥匙串内部的秘密也会在备份中被加密. 钥匙串本身的密码不会被备份. 这样一来, 密码和机密内容就无法被闯入系统备份中的人窃走. 基于这个原因, 在iPhone上使用钥匙串去保存数据和密码可以被安全的保存到网页站点上.

钥匙串的易用性

虽然钥匙串的结构提供了强大的功能和灵活性, 他也介绍了一个复杂的一面, 就是希望应用程序写入钥匙串最好不用处理这方面. 幸运的是. 你不必处理. 钥匙串服务API提供了一套好用的高层函数接口,来处理钥匙串的操作.

iOS钥匙串服务的字典搜索

在iOS中, 钥匙串服务使用键值对的字典来表示我们想要查找或创建的钥匙串内容. 一个典型的搜索字典的组成:

其中属性数据的指定是取决于你想要搜索的类的项目. 比如: 如果你为类 kSecClass 指定了 kSecClassGenericPassword 的值, 你可以创建或修改数据内容, 但内容不能是对象,因为指定的类为密码.

比如你想要执行一个大小写不敏感的搜索,搜索名字为”ImaUser”的Appstore账号的密码,你可以按照下面的格式创建字典:

在返回值中指定了kSecReturnData, 代表会直接返回密码, 如果你想要返回整个数据的字典,可以在返回值中指定 kSecReturnAttributes 的键,对应的值为kCFBooleanTrue.

iOS钥匙串的任务

基本的任务:

将钥匙串服务添加到你的应用中

大多数的iOS应用需要应用钥匙串,基本使用服务:添加密码到钥匙串,修改存在的钥匙串内容,读取钥匙串内容. 钥匙串服务为我们提供了几个方法来实现这些功能:

你可以使用互联网的密码访问站点, 也可以使用普通的密码访问其他的受密码保护的服务. 在iOS钥匙串服务中, 证书,密钥, 身份认证都视作密码,除非有不同的属性定义.

下图展示了一个应用程序如何访问FTP服务的:

开始用户选择了FTP服务, 应用程序调用钥匙串服务的SecItemCopyMatching方法, 传入包含属性的字典,如果密码存在钥匙串中, 方法将密码返回给应用程序,然后传给FTP服务器进行认用户认证. 认证成功流程结束, 认证失败的话, FTP服务会弹出对话框让用户输入用户名和密码. 如果密码没有存在钥匙串中, SecItemCopyMatching 方法会返回 errSecItemNotFound 状态码, 然后会弹出对话框要求用户输入账号和密码, 当认证结束后,会提示用户是否将密码存储到钥匙串中,如果用户选择否,流程结束,如果用户选择是, 应用程序会调用钥匙串服务的SecItemAdd方法添加(如果之前没有), 或调用SecItemUpdate来更新(之前有), 流程结束.

钥匙串的示例代码在这里 参考 Keychain Services Programming Guide