转自http://my.oschina.net/w11h22j33/blog/206713


一、Keychain 基础

根据苹果的介绍,iOS设备中的Keychain是一个安全的存储容器,可以用来为不同应用保存敏感信息比如用户名,密码,网络密码,认证令牌。苹果自己用keychain来保存Wi-Fi网络密码,VPN凭证等等。它是一个sqlite数据库,位于/private/var/Keychains/keychain-2.db,其保存的所有数据都是加密过的。

开发者通常会希望能够利用操作系统提供的功能来保存凭证(credentials)而不是把它们(凭证)保存到NSUserDefaults,plist文件等地方。保存这些数据的原因是开发者不想用户每次都要登录,因此会把认证信息保存到设备上的某个地方并且在用户再次打开应用的时候用这些数据自动登录。Keychain的信息是存在于每个应用(app)的沙盒之外的。

通过keychain access groups可以在应用之间共享keychain中的数据。要求在保存数据到keychain的时候指定group。把数据保存到keychain的最好方法就是用苹果提供的KeychainItemWrapper。可以到这下载例子工程。第一步就是创建这个类的实例。

KeychainItemWrapper *wrapper = [[KeychainItemWrapper alloc] initWithIdentifier:@”Password” accessGroup:nil];

标识符(Identifier)在后面我们要从keychain中取数据的时候会用到。如果你想要在应用之间共享信息,那么你需要指定访问组(access group)。有同样的访问组 的应用能够访问同样的keychain信息。

KeychainItemWrapper *wrapper = [[KeychainItemWrapper alloc] initWithIdentifier:@”Account Number” accessGroup:@”YOUR_APP_ID_HERE.com.yourcompany.GenericKeychainSuite”];

要把信息保存到keychain中,使用 setObject:forKey: 方法。在这里, (id)kSecAttrAccount 是一个预先定义好的键(key),我们可以用它来保存账号名称。 kSecClass指定了我们要保存的某类信息,在这里是一个通用的密码。kSecValueData可以被用来保存任意的数据,在这里是一个密码。

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

[wrapper setObject:@”username” forKey:(id)kSecAttrAccount];

[wrapper setObject:@”password”forKey:(id)kSecValueData];

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

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

你可以从如下对苹果的文档的截图看到。

当然,我们应该绝对不要使用kSecAttrAccessibleAlways。一个安全点的选项是kSecAttrAccessibleWhenUnlocked。有些选项是以 ThisDeviceOnly 结尾的,如果选中了这个选项,那么数据就会被以硬件相关的密钥(key)加密,因此不能被传输到或者被其他设备看到。即使它们提供了进一步的安全性,使用它们可能不是一个好主意,除非你有一个更好的理由不允许数据在备份之间迁移。

要从keychain中获取数据,可以用 NSString *accountName = [wrapper objectForKey:(id)kSecAttrAccount];

钥匙串中的条目称为SecItem,但它是存储在CFDictionary中的。SecItemRef类型并不存在。SecItem有五类:通用密码、互联网密码、证书、密钥和身份。在大多数情况下,我们用到的都是通用密码。许多问题都是开发人员尝试用互联网密码造成的。互联网密码要复杂得多,而且相比之下优势寥寥无几,除非开发Web浏览器,否则没必要用它。KeyChainItemWrapper只使用通用密码,这也是我喜欢它的原因之一。iOS应用很少将密钥和身份存储起来,所以我们在本书中不会讨论这方面的内容。只有公钥的证书通常应该存储在文件中,而不是钥匙串中。

最后,我们需要在钥匙串中搜索需要的内容。密钥有很多个部分可用来搜索,但最好的办法是将自己的标识符赋给它,然后搜索。通用密码条目都包含属性kSecAttrGeneric,可以用它来存储标识符。这也是KeyChainItemWrapper的处理方式。

钥匙串中的条目都有几个可搜索的属性和一个加密过的。对于通用密码条目,比较重要的属性有账户(kSecAttrAccount)、服务(kSecAttrService)和标识符(kSecAttrGeneric)。而值通常是密码。

说明:

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

安全性:

从Keychain中导出数据的最流行工具是ptoomey3的Keychain dumper。其github地址位于此。现在到这个地址把它下载下来。然后解压zip文件。在解压的文件夹内,我们感兴趣的文件是keychain_dumper这个二进制文件。一个应用能够访问的keychain数据是通过其entitlements文件指定的。keychain_dumper使用一个自签名文件,带有一个*通配符的entitlments,因此它能够访问keychain中的所有条目。 当然,也有其他方法来使得所有keychain信息都被授权,比如用一个包含所有访问组(access group)的entitlements文件,或者使用一个特定的访问组(access group)使得能够访问所有的keychain数据。 例如,工具Keychain-viewer就使用如下的entitlements.

虽然keychain也容易被破解,不过比NSUserDefaults和plist安全得多,只要我们注意不要在keychain中保存明文密码就会在很大程度上提升安全性。

二、Keychain操作

iOS中Security.framework框架提供了四个主要的方法来操作KeyChain:

// 查询
OSStatus SecItemCopyMatching(CFDictionaryRef query, CFTypeRef *result);// 添加
OSStatus SecItemAdd(CFDictionaryRef attributes, CFTypeRef *result);// 更新
KeyChain中的ItemOSStatus SecItemUpdate(CFDictionaryRef query, CFDictionaryRef attributesToUpdate);// 删除
KeyChain中的ItemOSStatus SecItemDelete(CFDictionaryRef query)

三、Keychain使用

引入Security包,引入文件#import <Security/Security.h>

添加

- (IBAction)add:(id)sender {if(nameField.text.length >0  && passwordField.text.length > 0) {NSMutableDictionary* dic = [NSMutableDictionary dictionary];[dic setObject:(id)kSecClassGenericPassword forKey:(id)kSecClass];[dic setObject:nameField.text forKey:()kSecAttrAccount];[dic setObject:[passwordField.text dataUsingEncoding:NSUTF8StringEncoding] forKey:(id)kSecValueData];OSStatus s = SecItemAdd((CFDictionaryRef)dic, NULL);NSLog(,s);}
}

查找

- (IBAction)sel:(id)sender {NSDictionary* query = [NSDictionary dictionaryWithObjectsAndKeys:kSecClassGenericPassword,kSecClass, kSecMatchLimitAll,kSecMatchLimit,kCFBooleanTrue,kSecReturnAttributes,nil];CFTypeRef result = nil;OSStatus s = SecItemCopyMatching((CFDictionaryRef)query, &result);NSLog(@"%@",s);NSLog(@"%@",result);
}- (IBAction)sname:(id)sender {if(nameField.text.length >0) {NSDictionary* query = [NSDictionary dictionaryWithObjectsAndKeys:kSecClassGenericPassword,kSecClass, nameField.text,kSecAttrAccount,kCFBooleanTrue,kSecReturnAttributes,nil];CFTypeRef result = nil;OSStatus s = SecItemCopyMatching((CFDictionaryRef)query, &result);NSLog(@"%@",s);          NSLog(@"%@",result);        if(s == noErr) {NSMutableDictionary* dic = [NSMutableDictionary dictionaryWithDictionary:result];[dic setObject:(id)kCFBooleanTrue forKey:kSecReturnData];[dic setObject:[query objectForKey:kSecClass] forKey:kSecClass];NSData* data = nil;if(SecItemCopyMatching((CFDictionaryRef)dic, (CFTypeRef*)&data) == noErr) {if(data.length)NSLog(@"%@",[[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] autorelease]);}}}
}

修改

- (IBAction)update:(id)sender {if(nameField.text.length > 0 && passwordField.text.length >0 ) {NSDictionary* query = [NSDictionary dictionaryWithObjectsAndKeys:kSecClassGenericPassword,kSecClass, nameField.text,kSecAttrAccount,kCFBooleanTrue,kSecReturnAttributes,nil];CFTypeRef result = nil;if(SecItemCopyMatching((CFDictionaryRef)query, &result) == noErr){    NSMutableDictionary* update = [NSMutableDictionary dictionaryWithDictionary:(NSDictionary*)result];[update setObject:[query objectForKey:kSecClass] forKey:kSecClass];[update setObject:[passwordField.text dataUsingEncoding:NSUTF8StringEncoding] forKey:kSecValueData];[update removeObjectForKey:kSecClass];TARGET_IPHONE_SIMULATOR[update removeObjectForKey:(id)kSecAttrAccessGroup];NSMutableDictionary* updateItem = [NSMutableDictionary dictionaryWithDictionary:result];[updateItem setObject:[query objectForKey:(id)kSecClass] forKey:(id)kSecClass];OSStatus status = SecItemUpdate((CFDictionaryRef)updateItem, (CFDictionaryRef)update);NSLog(,status);}}
}

删除

- (IBAction)del:(id)sender {if(nameField.text.length >0) {NSDictionary* query = [NSDictionary dictionaryWithObjectsAndKeys:kSecClassGenericPassword,kSecClass, nameField.text,kSecAttrAccount,nil];OSStatus status = SecItemDelete((CFDictionaryRef)query);NSLog(,status);         }
}

注意:

1.区别(标识)一个item要用kSecAttrAccount和kSecAttrService

IOS KeyChain相关推荐

  1. ios keychain 不被清理_iOS签名机制和说明文件【ios企业签名吧】

    IOS签名机制和配置文件.iOS签名机制的作用:保证安装在手机上的应用程序经苹果公式验证和许可.无论是真机调试还是发布App,开发人员都必须经过一些复杂的步骤.以下广州贝壳技术将详细说明. 贝壳科技( ...

  2. iOS keyChain 研究

    一.基本知识 1.方法 SecItemAdd 增 SecItemUpdate 改 SecItemDelete 删 SecItemCopyMatching 查 2.权限 文档上说iOS的keyChain ...

  3. iOS Keychain(钥匙串)原理及使用

    Keychain介绍 Keychain Services 是 macOS 和 iOS 都提供一种安全的存储敏感信息的工具,比如,网络密码:用户访问服务器或者网站,通用密码:用来保存应用程序或者数据库密 ...

  4. html5 ios keychain,iOS Keychain理解

    Keychain 介绍 Keychain Services 是 OS X 和 iOS 都提供一种安全地存储敏感信息的工具,比如,存储用户ID,密码,和证书等.存储这些信息可以免除用户重复输入用户名和密 ...

  5. iOS KeyChain使用

    最近项目需要存储用户的唯一标识符,但是由于如果用户重装APP,获取到的又会是一个新的UDID.查询了一系列资料下来,可以用Keychain进行存储UDID,然后就算重装了APP,也能从Keychain ...

  6. iOS Keychain和keychain share

    一.keychain介绍(摘抄别人的https://blog.hudongdong.com/ios/356.html) 根据苹果的介绍,iOS设备中的Keychain是一个安全的存储容器,可以用来为不 ...

  7. html5 ios keychain,iOS 用keychain钥匙串保存账号、设备UUID及APP间共享

    iOS的keychain服务提供了一种安全的保存私密信息(密码,序列号,证书等)的方式,每个ios程序都有一个独立的keychain存储.相对于NSUserDefaults.文件保存等一般方式,key ...

  8. html5 ios keychain,iOS10适配之Keychain读写失败

    Keychain iOS设备中的Keychain是一个安全的存储容器,可以用来为不同应用保存敏感信息比如用户名,密码,网络密码,认证令牌,UUID等 Bug 升级正式版Xcode8 运行了下最近的项目 ...

  9. iOS Keychain钥匙串应用间数据共享

    在一个公司中可能有多款产品.对于用户而言,一般使用一个帐号就可以登陆访问该公司的所有的产品.对于这种情况,如果一款手机中装了该公司的两款(或多款)产品,那么我们希望只在其中一款产品中登陆,那么另一款产 ...

最新文章

  1. Linux中如何添加/删除FTP用户并设置权限
  2. 索引与优化like查询
  3. bzoj-3288 3288: Mato矩阵(数论)
  4. Jenkins中连接Git仓库时提示:无法连接仓库:Error performing git command: git ls-remote -h
  5. sql注入学习——布尔盲注
  6. 计算机游戏 综述,计算机游戏对玩家认知能力影响的研究综述
  7. Vulhub 靶场安装
  8. andriod sqlite 详解转载
  9. ProjectFileManager 发布!项目文件管理效率提升10倍以上!
  10. echarts词云图形状_词云图在自然语言中的应用,可以如此炫酷!
  11. Eclipse中文显示乱码问题
  12. gauge对应的JAVA类型_spring boot 源码解析38-GaugeService详解
  13. 电脑突然调节不了亮度?让我教你来恢复
  14. AMESim 14.0 win10环境下安装教程
  15. 8255实现数码显示管显示两位数字
  16. Mac 共享WiFi给任意设备(Android,Iphone等等)
  17. Windows 下设置自定义域名解析到指定 IP
  18. 计算机关闭应用窗口的方法,电脑怎么从后台关闭程序应用
  19. 解决Windows Firewall/Internet Connection Sharing (ICS)服务无法启动(ping通IP,但不能浏览网页)
  20. win10系统potplay播放器关闭自动更新方法

热门文章

  1. css样式中的vw什么意思,css中vw是什么意思?
  2. 开发知识竞赛答题活动小程序过程中使用到的实用工具库介绍
  3. 计算机毕业设计-基于springboot的电影院会员管理系统(项目+文档+ppt)
  4. 机器学习笔记之玻尔兹曼机(一)基本介绍
  5. Docker从安装到部署JAVA应用
  6. HSSFCellStyle样式详解
  7. Go 框架 iris 文档
  8. 离散数学 第二章-一阶逻辑
  9. Adobe Lightroom Classic CC 2020 Mac(lr cc 2020 mac)
  10. excel 汉字转拼音/汉字提取首拼