iOS 再谈Keychain钥匙串,应用间数据共享打造iOS上的全家桶

我知道没Demo看博客很痛苦,所以Demo先行:https://github.com/rayshen/GIKeychainGroupDemo

该demo里有2个工程,你先运行任何一个会存储一个值,再运行另一个会访问之前的app存储的值,并修改。

官方:https://developer.apple.com/library/ios/samplecode/GenericKeychain/Introduction/Intro.html

之前博客使用过Keychain,实现了数据删除APP后还能保存,但是并没有实现APP间的共享。

实现APP间的数据共享,主要依赖于在数据存入钥匙串时,使用同一个钥匙串条目。

主要分为两部分:

1.赋予应用对某个钥匙串条目的访问权限。

2.写入时配置钥匙串条目,对kSecAttrAccessGroup的值进行设置。

一、APP对钥匙串的访问权限:

(1)未对应用APP的entitlement(授权)进行配置时,APP使用钥匙串存储时,会默认存储在自身BundleID的条目下。

(2)对APP的entitlement(授权)进行配置后,说明APP有了对某个条目的访问权限。

钥匙串的可视化效果可参见Mac的APP-钥匙串访问。

APP钥匙串访问权限的配置方法:

1.新建一个Plist文件,在Plist中的数组中添加可以访问的条目的名字(如KeychainAccessGroups.plist),结构如下:

Plist代码:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>keychain-access-groups</key>
    <array>
        <string>XXXXX.GrassInfoAppFamily</string>
    </array>
</dict>
</plist>

2.在Build-setting中进行配置,搜索entitlement,注意路径别配置错:

二、APP对钥匙串的操作:

钥匙串的操作接口都位于Security.framework框架下,它是一个sqlite数据库,位于/private/var/Keychains/keychain-2.db,其保存的所有数据都是加密过的。

其过程可以总结为:

1.配置查询字典,格式是NSMutableDictionary,需要配置的内容下次再分析,功能就相当于写一句SQL一样。

2.进行增(SecItemAdd)、删(SecItemDelete)、改(SecItemUpdate)、查(SecItemCopyMatching)。

代码Demo里面有,这里以增为例,下面有2个语句,一个是增加到自身BundleID的钥匙串条目,一个是增加到共享的条目中。

//创建一个基本的查询字典
+ (NSMutableDictionary *)getKeychainQuery:(NSString *)service {
    return [NSMutableDictionary dictionaryWithObjectsAndKeys:
            (__bridge id)kSecClassGenericPassword,(__bridge id)kSecClass,
            service, (__bridge id)kSecAttrService,
            service, (__bridge id)kSecAttrAccount,
            (__bridge id)kSecAttrAccessibleAfterFirstUnlock,(__bridge id)kSecAttrAccessible,
            nil];
}

+ (void)addKeychainData:(id)data forKey:(NSString *)key{
    //Get search dictionary
    NSMutableDictionary *keychainQuery = [self getKeychainQuery:key];
    //Delete old item before add new item
    SecItemDelete((__bridge CFDictionaryRef)keychainQuery);
    //Add new object to search dictionary(Attention:the data format)
    [keychainQuery setObject:[NSKeyedArchiver archivedDataWithRootObject:data] forKey:(__bridge id)kSecValueData];
    //Add item to keychain with the search dictionary
    SecItemAdd((__bridge CFDictionaryRef)keychainQuery, NULL);
}

+(void)addShareKeyChainData:(id)data forKey:(NSString *)key{
    //Get search dictionary
    NSMutableDictionary *keychainQuery = [self getKeychainQuery:key];
    [keychainQuery setObject:accessGroupItem forKey:(id)kSecAttrAccessGroup];
    //Delete old item before add new item
    SecItemDelete((__bridge CFDictionaryRef)keychainQuery);
    //Add new object to search dictionary(Attention:the data format)
    [keychainQuery setObject:[NSKeyedArchiver archivedDataWithRootObject:data] forKey:(__bridge id)kSecValueData];
    //Add item to keychain with the search dictionary
    SecItemAdd((__bridge CFDictionaryRef)keychainQuery, NULL);
}

函数  [keychainQuery setObject:accessGroupItem forKey:(id)kSecAttrAccessGroup] 的配置,就是指定了这次写入时的钥匙串条目,不写入时默认会写入自身BundleID的条目下

在查询中,也可以对查询的钥匙串沙盒进行配置,默认会对所有有权限的条目进行搜索。

三、keychain的组成:

参考博客:http://my.oschina.net/w11h22j33/blog/206713

每一个keyChain的组成如图,整体是一个字典结构.
1.kSecClass key 定义属于那一种类型的keyChain
2.不同的类型包含不同的Attributes,这些attributes定义了这个item的具体信息
3.每个item可以包含一个密码项来存储对应的密码

对于最常用密码类型,我们应该如下配置

[wrapper setObject:kSecClassGenericPassword forKey:(id)kSecClass];//class

[wrapper setObject:@"username" forKey:(id)kSecAttrAccount];//key

[wrapper setObject:@"password"forKey:(id)kSecValueData];//value

[wrapper setObject:(id)kSecAttrAccessibleAlwaysThisDeviceOnly forKey:(id)kSecAttrAccessible];

kSecAttrAccessiblein变量用来指定这个应用合适需要访问这个数据。我们需要对这个选项特别注意,并且使用最严格的选项。这个键(key)可以设置6种值。

你可以参考以下:

四、安全

最后,再来个大招。。。

前面说到,APP能够访问的keychain数据是通过其entitlements文件指定的。

但是!!!如果使用带有一个*通配符的entitlments,因此它能够访问keychain中的所有条目。。。

或者,如果用一个包含所有访问组(access group)的entitlements文件,也能够访问所有的keychain数据。比如你在自己的plist文件中的声明了别人的BundleID,那么那个人默认存的钥匙串条目就能被你访问到……(我受到了惊吓。。)

但假如你的应用带*通配符的entitlments能不能上架就不得而知了……

因为说明,这钥匙串不是安全的,要存钥匙串,还得加密啊同学们。

时间: 2024-10-12 19:44:27

iOS 再谈Keychain钥匙串,应用间数据共享打造iOS上的全家桶的相关文章

Java基础——再谈面向对象

去年的这个时候,心血来潮写了篇<简述面向对象技术>,先在看来不由的会想:这都是写的什么跟什么啊?(ps:虽然现在写的博客依然不咋地)但是,Java的学习中又一次不得不再一次面向对象,所以,奉上一篇<再谈面向对象>,做为新年的一盘开胃菜. 面向对象是相对于面向过程而言,是一种思想. 区别于面向过程: 面向过程是以函数为基础,完成各种操作,强调的是过程,而面向对象是以对象为基础,强调的是对象. 比如说把大象装进冰箱分为几步,宋丹丹是这样说的:三步呗, 第一步:打开冰箱门, 第二步:把大

从飞信群再谈时间管理

收邮件啊 快收邮件~取消飞信小群的当天晚上,便有几位小组组长跑到某某那如是说.虽然我没有做过调查,但是看到这样的情景,我想她们应该和我有一样的感觉,没有了飞信小群在一定程度上,不 -方 -便- 但是过了这一段时间之后,发现我们日常的学习并没有受到什么影响,反倒是比之前明显的改善了.下面谈谈我对这件事的看法. 首先我们还是有飞信大群的.因为不会经常通知,也就谈不上打扰,而且也保证了紧急情况下的及时性和效率.可小群不一样.小群的人数不多,但通知频繁.这样问题就随之来了.最近我的体会 优点一减少打扰

再谈如何学习

大家看看这样的对比: 1,没有思考的学习: 通常有下列四类基本的结构: ⑴集合结构.该结构的数据元素间的关系是"属于同一个集合". ⑵线性结构.该结构的数据元素之间存在着一对一的关系. ⑶树型结构.该结构的数据元素之间存在着一对多的关系. ⑷图形结构.该结构的数据元素之间存在着多对多的关系,也称网状结构. 2,经过简单思考的学习: ⑴集合."属于同一个集合". ⑵线性.一对一. ⑶树型.一对多. ⑷图形.多对多,也称网状结构. 思考:我们该如何高效学习 对于第一部分

Another Look at Events(再谈Events)

转载:http://www.qtcn.org/bbs/simple/?t31383.html Another Look at Events(再谈Events) 最近在学习Qt事件处理的时候发现一篇很不错的文章,是2004年季刊的一篇文章,网上有这篇文章的翻译版,但是感觉部分地方翻译的比较粗糙,不是很明确.索性重新翻译了一遍,并引用了原翻译版的一段译注.以下都是用自己能理解的方式来翻译的,由于水平有限,有很多不足的地方,希望大家指正. Another Look at Events (再谈Event

再谈怎样学习

大家看看这种对照: 1,没有思考的学习: 通常有下列四类主要的结构: ⑴集合结构.该结构的数据元素间的关系是"属于同一个集合". ⑵线性结构.该结构的数据元素之间存在着一对一的关系. ⑶树型结构.该结构的数据元素之间存在着一对多的关系. ⑷图形结构.该结构的数据元素之间存在着多对多的关系,也称网状结构. 2,经过简单思考的学习: ⑴集合."属于同一个集合". ⑵线性.一对一. ⑶树型.一对多. ⑷图形.多对多,也称网状结构. 思考:我们该怎样高效学习 对于第一部分,

iOS编程——经过UUID和KeyChain来代替Mac地址实现iOS设备的唯一标示(OC版)

iOS编程——通过UUID和KeyChain来代替Mac地址实现iOS设备的唯一标示(OC版) 很多的应用都需要用到手机的唯一标示,而且要求这个唯一标示不能因为应用app的卸载或者改变而变化. 在iOS7以前是可以通过Mac地址来实现这个功能的,但是iOS7(包含)以后是无法获得Mac地址的:苹果官方推荐使用UUID,但是每次随着APP的卸载重装,UUID会随之发生变化,那该如何处理呢? 我们需要一个能在app卸载重装后不会改变的值,而keyChain恰巧就可以做到.配合UUID就可以实现了!让

再谈QVector与QByteArray——Qt的写时复制(copy on write)技术

Qt作为一个优秀的跨平台开源C++框架,如果我们只停留在使用它的基础上而不深挖其实现手法,实在是浪费这个知识宝库了~我们在之前的博文QVector的内存分配策略与再谈QVector与std::vector--使用装饰者让std::vector支持连续赋值中简单聊了聊QVector内存分配和赋值方面的一点东西,今天接着从QVector展开谈谈Qt的写时复制技术.老实说,"隐式共享,引用计数,写时复制"也是老调重弹的话题了,不过也是QTL与STL最大的区别之一,这篇博文不详谈"写

再谈通过http访问SSAS

问题: 在有些场景下,数据中心会分为不同的服务器场:数据库场和应用程序场.服务器场间有严格的防火墙控制,其中数据库场只能建立从应用程序场的防火墙穿越,也就是说不允许任何客户端直接连接到防火墙. 这种策略对于数据库引擎来说没什么问题,但是对于分析服务来说就被完全限制住了,通常我们都是通过Excel直接连接分析服务数据库的,并且通过分析服务的角色来控制对数据的访问权限.那么是否有什么方法可以解决这个问题呢? 解决思路: 我们知道SSAS是可以通过http的方式来访问的,那么我们只要让这个站点接受wi

通过SharedPreferences实现进程间数据共享的问题详解

??之前为了解决应用的内存压力,在同一个应用中使用了多进程,但在程序自测的过程中发现不同进程之间的SharedPreferences数据不能共享,但应用内很多数据都是通过SharedPreferences来保存的,如果改成其它多进程通信的方式改动比较大.通过查看源码发现,在API Level>=11即Android 3.0可以通过Context.MODE_MULTI_PROCESS属性来实现SharedPreferences多进程共享,具体使用方式如下: SharedPreferences sp