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