iOS Keychain钥匙原理及使用 Keychain介绍Keychain的结构Keychain的特点Keychain的使用用户密码iOS 应用间共享 Keychain 数据

Keychain介绍

Keychain Services 是 macOS 和 iOS 都提供一种安全的存储敏感信息的工具,比如,网络密码:用户访问服务器或者网站,通用密码:用来保存应用程序或者数据库密码.与此同时,用于认证的证书,密钥,和身份信息,也可以存储在Keychain中,Keychain Services 的安全机制保证了存储这些敏感信息不会被窃取。简单说来,Keychain 就是一个安全容器。

在iOS中keychian 依赖用于签名的provisioning profile描述文件,确保发布不同版本的时候使用同一个pp文件 Keychain的结构

如上图,每一个keyChain的组成如图,整体是一个字典结构.

kSecClass key 定义属于那一种类型的keyChain(通用密码、互联网密码、证书、密钥和身份)不同的类型包含不同的Attributes,这些attributes定义了这个item的具体信息每个item可以包含一个密码项来存储对应的密码

Keychain可以包含任意数量的keychain item(keychain item称为SecItem,但它是存储在CFDictionary中的).每一个keychain item包含数据和一组属性。SecItem有五类:通用密码、互联网密码、证书、密钥和身份。在大多数情况下,我们用到的都是通用密码

在macOS中,当keychain被锁的时候加密的item没办法访问,如果你想要该问被锁的item,就会弹出一个对话框,需要你输入对应keychain的密码。当然,未有密码的keychain你可以随时访问。但在iOS中,你只可以访问你自已的keychain items

Keychain的特点

数据并不存放在App的Sanbox中,即使删除了App,资料依然保存在keychain中。如果重新安装了app,还可以从keychain获取数据。

keychain的数据可以通过group方式,让程序可以在App间共享。不过得要相同TeamID

keychain的数据是经过加密的

Keychain的使用

Apple针对keychain也提供了丰富的开发文档说明,包括有Keychain Services Programming Guide:文章中包含了使用mac和ios的keychain开发,首先介绍的是keychain的基本功能和概念,然后还有一个基本的例子介绍了基本的使用keychain API的方法

对于每一个应用来说,KeyChain都有两个访问区,私有区和公共区。私有区是一个sandbox,本程序存储的任何数据都对其他程序不可见,其他应用程序无法访问该区数据。如果要想将存储的内容放在公共区,实现多个应用程序间可以共同访问一些数据,则可以先声明公共区的名称,官方文档管这个名称叫“keychain access group”

这里我们先介绍 KeyChain 私有区的访问存储,即该私有区只能给自己程序使用。比如保存用户密码,设备唯一码(UDID)等等

用户密码

大多数iOS应用需要用到Keychain, 都用来添加一个密码,修改一个已存在Keychain item或者取回密码。Keychain提供了以下的操作

SecItemAdd 添加一个item

SecItemUpdate 更新已存在的item

SecItemCopyMatching 搜索一个已存在的item

SecItemDelete 删除一个keychain item

当然对于只需要保存用户名和密码的应用来说,SSKeyChain可能更加适合,它对keychain做了相应的封装,接口相对来说更加简单
通过以下类方法来使用SSKeyChain(请查看SSKeyChain.h

+ (NSArray *)allAccounts;+ (NSArray *)accountsForService:(NSString *)serviceName;+ (NSString *)passwordForService:(NSString *)serviceNameaccount:(NSString *)account;+ (BOOL)deletePasswordForService:(NSString *)serviceNameaccount:(NSString *)account;+ (BOOL)setPassword:(NSString *)password forService:(NSString*)serviceName account:(NSString *)account;

SSKeyChain的方法中涉及到的变量主要有三个,分别是password、service、account。password、account分别保存的是密码和用户名信息。service保存的是服务的类型,就是用户名和密码是为什么应用保存的一个标志。比如一个用户可以在不同的论坛中使用相同的用户名和密码,那么service保存的信息分别标识不同的论坛。由于包名通常具有一定的唯一性,通常在程序中可以用包的名称来作为service的标识

iOS 应用间共享 Keychain 数据

在 iOS 3.0 之后,应用间共享 keychain 数据成为了一种可能。但这是被严格限制的,只有拥有相同 App ID 前缀的应用才有可能共享 keychai,并且各应用存储的 keychain item 都标记了相同的 kSecAccessGroup 字段值

相同的Team ID
有相同的 Team ID这个是应用间共享 Keychain 数据的前提条件。一个 App ID 分两部分:

Apple 为你生成的 Team ID开发者注册的 Bundle ID

一个典型的 App ID 如:GPZ8FX842Q.com.apple.app, GPZ8FX842Q即为你的Team ID,是 Apple 为你生成的

一个开发者账号可以有不同的几个 Team ID。但 Apple 不会为不同的开发者生成一样的 Team ID。这样,不同的开发者账号发布的应用想共享 keychain 数据,在现在来看是无法实现的。而要做到 Keychain 数据共享,要求是同一个开发账号开发的,同时选择了相同的 Team ID

打开Keychain Sharing权限

如图打开Keychain Sharing开关,设置好正确的 Keychain Group,设置好后应该会生成一个文件,如下图

并且会在 Project->build setting->Code Signing Entitlements 里自动配置这个文件的路径

配置好后,须用你正式的证书签名编译才可通过。否则xcode会弹框告诉你code signing有问题。所以,苹果限制了你只能同公司的产品共享KeyChain数据,别的公司访问不了你公司产品的KeyChain