开篇
数据安全是当下移动互联网发展至今最不可或缺的一个环节,移动互联网发展至今网络犯罪早已不再是靠简单的发诈骗短信这种方式为主了,带有技术性的网络诈骗技术这两年也是层出不穷。作为本人的第一篇文章就简单的谈谈在iOS开发中数据存储需要注意的一些问题
一、iOS系统中常见的数据存储方式
1.沙盒机制
每一个应用程序都有自己独立的沙盒,沙盒是用来保存用户数据的小型数据库、可以用文件夹的方式进行访问,沙盒只能由本身的应用程序访问,各个程序之间的沙盒不能彼此进行访问。
沙盒有以下几个部分组成
1.Documents:程序运行时生成的数据文件、比如:游戏进度存档等,该文件夹下的数据会进行数据上传
2.Library:Library下有两个文件夹,分别是Caches和Preferences。Caches存储的是应用程序下载的数据(视频。图片等等),Caches文件夹下的数据不会被上传。Preferences :存储的是该应用程序的偏好设置、会自动备份、通常用 NSUserDefaults创建出来的plist文件就保存在这个文件夹之下。
3.tmp:临时文件,应用程序结束后会该文件夹下的数据会被清除。
2.keyChain
iOS中的沙盒机制虽然在一定程度上(比较安卓)保证了数据安全性,但是不代表沙盒是不可攻破的,如果沙盒中存放的是用户名和密码那么安全性需要进一步加强,于是在这种情况下keyChain是一种不错的选择
苹果增加更安全的存储方式:Keychain(相对于NSUserDefaults数据以明文的形式保存在)提供了一种安全的保存私密信息(密码,序列号,证书等)的方式,每个ios程序都有一个独立的keychain存储,将数据加密后存储在本地,更安全。
二、沙盒存储方式的运用
通常情况下沙盒在数据存储方面一直是用来保存登录用户的用户名和密码,而这种实现方式的媒介就是NSUserDefaults,而用NSUserDefaults实例化对象是一个plist文件类型,这个plist存放位置是沙盒中的Library文件夹下
在实际开发过程中我们往往会封装一个工具类来实现沙盒存储存储
#import <Foundation/Foundation.h>
#import <CommonCrypto/CommonDigest.h>
#import "KeychainItemWrapper.h"
@interface CHBUserMsgManager : NSUserDefaults
#pragma mark - init CHBUserMsgManager
/** 创建CHBUserMsgManager对象 */
+ (instancetype)sharedTool;
/** MD5加密字符串 */
- (NSString *)encryptionNSString:(NSString *)str;
/** 存储基本的数据信息 */
- (void)saveMessageByNSDictionary:(NSDictionary *)dict;
/** 删除用户的所有信息 */
- (void)removeAllMessage;
#pragma mark - keyChain save
/** 保存数据 */
- (void)saveMsgByKeyChain:(NSString *)key content:(NSString *)content;
/** 获取保存的信息 */
- (NSString *)getKeyChainContent;
/** 清空keyChain中的数据 */
- (void)clearKeyChainMsg;
#pragma mark - get SandBox path
/** 获取沙盒路径 */
- (NSString *)getSanBoxPath;
/** 获取documents路径 */
- (NSString *)getDocumentsPath;
/** 获取Library路径 */
- (NSString *)getLibraryPath;
/** 获取caches路径 */
- (NSString *)getCachesPath;
/** 获取tmp路径 */
- (NSString *)getTmpPath;
在这个继承自NSUserDefaults的类中笔者创建了CHBUserMsgManager的初始化方法、沙盒下各个文件夹路径的获取方法、MD5加密方法、以及keyChain保存关键信息的方法。我们先来看一下传统的沙盒保存方法的操作:
- (void)saveMessageByNSDictionary:(NSDictionary *)dict
{
NSArray *allKeys = [dict allKeys];
CHBUserMsgManager *msgManager = [CHBUserMsgManager sharedTool];
for (int i = 0; i < allKeys.count; i ++) {
NSString *key = allKeys[i];
NSString *content = dict[key];
[msgManager setObject:content forKey:key];
}
[msgManager synchronize];
}
- (void)removeAllMessage
{
CHBUserMsgManager *msgManager = [CHBUserMsgManager sharedTool];
NSDictionary *dict = [msgManager dictionaryRepresentation];
for (NSString *key in [dict allKeys]) {
[msgManager removeObjectForKey:key];
[msgManager synchronize];
}
}
用沙盒保存信息的方法是通过plist实现的、而plist保存数据的方式是以key-value的形式实现的,所以在构建方法的时候只需要传入一个字典即可:
CHBUserMsgManager *manager = [CHBUserMsgManager sharedTool];
[manager saveMessageByNSDictionary:@{@"userName":@"CHBUserMsgManager",@"passWord":@"123456"}];
NSLog(@"%@",[manager getLibraryPath]);
根据打印出来的plist文件保存地址我们可以很轻松的找到该plist文件:
一般情况下这样存储用户名和密码的方式就是采用的这种安全性较低的方式。
MD5加密
上文简单的介绍了一下沙盒中存储方式的方法、但是缺点不言而喻,明文保存密码风险大、所以要想提高安全性,我们可以对密码进行MD5加密,如果有对MD5不太了解的可以点击这里。
笔者在对MD5的运用也是通过封装方法的形式实现的,这里只是简单的对字符串进行了加密,如果要将转换后的内容保存到plist文件中只需要和上文的方法进行结合就行,转化方法如下:
- (NSString *)encryptionNSString:(NSString *)str
{
const char *content = [str UTF8String];
unsigned char mdc[16];
CC_MD5(content, (CC_LONG)strlen(content), mdc);
NSMutableString *md5String = [NSMutableString string];
for (int i = 0; i < 16; i ++) {
[md5String appendFormat:@"%02x",mdc[i]];
}
return md5String;
}
注意要想用MD5进行加密,一定要引入头文件!!!!
#import <CommonCrypto/CommonDigest.h>
好了,现在看看运行效果如何:
在这里需要注意的问题是虽然原则上MD5是不可逆的,但是简单MD5数据可以通过相关的工具还原比如:
随意在密码设置上需要注意的是尽量设置的复杂一些。
最后谈一谈keyChain
keyChain存储用户信息更加安全,一般的调用方式比较多,在这里我用的是KeychainItemWrapper、导入头文件之后在工具类中是这样的:
#pragma mark - keyChain save
/** 保存数据 */
- (void)saveMsgByKeyChain:(NSString *)key content:(NSString *)content;
/** 获取保存的信息 */
- (NSString *)getKeyChainContent;
/** 清空keyChain中的数据 */
- (void)clearKeyChainMsg;
.m中实现部分:
- (void)saveMsgByKeyChain:(NSString *)key content:(NSString *)content
{
KeychainItemWrapper *keyChain = [[KeychainItemWrapper alloc] initWithIdentifier:keyStr accessGroup:nil];
[keyChain setObject:content forKey:(id)kSecValueData];
}
- (NSString *)getKeyChainContent
{
KeychainItemWrapper *keyChain = [[KeychainItemWrapper alloc] initWithIdentifier:keyStr accessGroup:nil];
return [keyChain objectForKey:(id)kSecValueData];
}
- (void)clearKeyChainMsg
{
KeychainItemWrapper *keyChain = [[KeychainItemWrapper alloc] initWithIdentifier:keyStr accessGroup:nil];
[keyChain resetKeychainItem];
}
调用起来也是比较简单的、keyChain这一块没有进行具体的操作实践,有兴趣的朋友可以自己试试,因为本人学习iOS时间并不是很长,所以对数据安全的理解可能比较肤浅,其实还是有很多地方可以深入学习的比如MD5加密之后还可以进行加盐操作,以及发送网络数据请求过程中�对于用户的关键信息也应该和后台人员进行沟通,制定相关的规则,来保证数据的安全。
在这里附上本文的demo:我的github
最后,如果本篇文章有什么理解不到位或者需要更正的地方希望大家能提出来,毕竟,技术在交流中才能进步!