iOS APP之本地数据存储(译)

  最近工做中完成了项目的用户信息本地存储,查阅了一些本地存储加密方法等相关资料。期间发现了一个来自印度理工学院(IIT)的信息安全工程师的我的博客,写了大量有关iOS Application security的文章。ios

   我的感受写的还不错,实用性比较强,加之阅读难度不大,因而趁着工做日无聊之际,小翻译了一篇。git

   原文IOS Application Security Part 20 – Local Data Storage (NSUserDefaults, CoreData, Sqlite, Plist files)地址http://highaltitudehacks.com/2013/10/26/ios-application-security-part-20-local-data-storage-nsuserdefaults/github

真的不难,仍是建议你们阅读原文。OK,废话很少说。上译文:sql

iOS应用安全(20) - 本地数据存储

-2013.10.26缓存

-发表自Prateek Gianchandani安全

   在这篇文章中,咱们将要看看应用中存储数据到本地的一些不一样的方法以及这些方法的安全性。app

  

咱们将会在一个demo上这些这些测试,你能够从个人github帐号上下载这个例子程序。对于CoreData的例子,你能够从下载例子程序。本例有一个不一样点就是咱们将会在模拟器上运行这些应用,而不是在设备上运行。这样作的目的是为了证实在前面文章中的操做均可以经过Xcode来把这些应用运行在模拟器上。固然,你也可使用前面文章中的步骤把这应用安装到设备上。ide


NSUserDefaults

  保存用户信息和属性的一个很是普通的方法就是使用NSUserDefaults。保存在NSUserDefaults中的信息在 你的应用关闭后再次打开以后依然存在。保存信息到NSUserDefaults的一个例子就是保存用户是否已登陆的状态。咱们把用户的登陆状态保存到 NSUserDefaults以便用户关闭应用再次打开应用的时候,应用可以从NSUserDefaults获取数据,根据用户是否登陆展现不一样的界面。 有些应用也用这个功能来保存机密数据,好比用户的访问令牌,以便下次应用登陆的时候,它们可以使用这个令牌来再次认证用户。工具

  从个人github能够下载例子应用,运行起来。你能够获得下面的界面,如今输入一些信息到与NSUserDefaults相关的文本框,而后点击下面的“Save in NSUserDefaults”。这样数据就保存到NSUserDefaults了。测试

  许多人不知道的是保存到NSUserDefaults的数据并无加密,所以能够很容易的从应用的包中看到。 NSUserDefaults被存在一个以应用的bundle id为名称的plist文件中。 首先,咱们须要找到咱们应用的bundle id。由于咱们在模拟器上运行,咱们能够在/Users/$username/Library/Application Support/iPhone Simulator/$ios version of simulator/Applications/找到应用。我这的路径是:“Users/prateekgianchandani/Library /Application Support/iPhone Simulator/6.1/Applications”。

  一旦咱们找到那个目录,咱们能够看到一堆应用。咱们能够用最近修改的日期找到咱们的应用,由于它是最近修改的。

  进入到应用的bundle里面。经过NSUserDefaults保存的数据均可以在以下图所示的Library -> Preferences -> $AppBundleId.plist文件中找到。

  打开这个plist文件,咱们能够清楚的看到这个文件的内容。

  有时候,plist文件会以二进制格式保存,所以可能第一下看到会以为不可读。你能够用plutil工具把它转成xml格式,或者直接用iExplorer在设备上查看。


Plist 文件

  另外一种保存数据广泛用的方法就是plist文件。Plist文件应该始终被用来保存那些非机密的文件,由于它们没有加密,所以即便在非越狱的设备上也很是容易被获取。已经有漏洞被爆出来,大公司把机密数据好比访问令牌,用户名和密码保存到plist文件中。在下面的demo中,咱们输入一些信息并保存到plist文件。

  下面是把数据保存到plist文件的代码。

 
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *filePath = [documentsDirectory stringByAppendingString:@"/userInfo.plist"];
NSMutableDictionary* plist = [[NSMutableDictionary alloc] init];
[plist setValue:self.usernameTextField.text forKey:@"username"];
[plist setValue:self.passwordTextField.text forKey:@"passwprd"];
[plist writeToFile:filePath atomically:YES];
 

  如你所见,咱们可以给plist文件指定路径。咱们能够搜索整个应用的全部plist文件。在这里,咱们找到一个叫作userinfo.plist的文件。

  能够看到,它包含了咱们刚刚输入的用户名/密码的组合。

CoreData和Sqlite文件

  由于CoreData内部使用Sqlite来保存信息,所以咱们这里将只会介绍下CoreData。若是你不知道什么是CoreData,下面是从苹果文档介绍CoreData截的图。

  所以,基本上,CoreData能够用来建立一个model,管理不一样对象的关系,把数据保存到本地,而后当你查询的时候从本地缓存中获取它们。本例中,咱们将使用一个demo,位于github。运行起来,你会发现它只是一个简单的RSS feed。

  这个应用用CoreData保存数据。一个很是重要的一点就是CoreData内部使用sql,所以全部文件都以.db文件保存。咱们到这个app的bundle中去看看。 在这个app的bundle中,你能够看到那里有一个MyCoreData.sqlite的文件。

  咱们能够用sqlite3分析。我这slite文件的地址是:~/Library/Application Support/iPhone Simulator/6.1/Applications/51038055-3CEC-4D90-98B8-A70BF12C7E9D/Documents.

  咱们能够看到,这里有个叫作ZSTORIES的表。在Core Data中,每一个表名开头都会被追加一个Z。这意味着真正的实体名称是STORIES,如咱们在工程的源码文件看到的那样。

  咱们能够很是容易的导出这个表的全部值。请却表headers的状态是on。

  正如咱们看到的那样,默认的,保存在CoreData的数据都是没有加密的,所以能够轻易的被取出。所以,咱们不该该用 CoreData保存机密数据。 有些库包装了一下CoreData, 声称可以保存加密数据。也有些库可以把数据加密保存到设备上,不过不使用CoreData。例如,Salesforce Mobile SDK 就使用了一个被称为SmartStore的功能来把加密数据以"Soups"的形式保存到设备上。


Keychain

  有些开发者不太喜欢把数据保存到Keychain中,由于实现起来不那么直观。不过,把信息保存到Keychain中多是非越狱设备上最安全的一种保存数据的方式了而在越狱设备上,没有任何事情是安全的。这篇文章展 示了使用一个简单的wrapper类,把数据保存到keychain是多么的简单。使用这个wrapper来保存数据到keychain就像把数据保存到 NSUserDefaults那么简单。下面就是一段把字符串保存到keychain的代码。请注意和使用NSUserDefaults的语法很是相似。

 
PDKeychainBindings *bindings = [PDKeychainBindings sharedKeychainBindings];
[bindings setObject:@"XYZ" forKey:@"authToken"];
下面是一段从keychain中取数据的代码。
PDKeychainBindings *bindings = [PDKeychainBindings sharedKeychainBindings];
NSLog(@"Auth token is %@",[bindings objectForKey:@"authToken"]]);
 

一些小技巧

  正如以前讨论过的那样,没有任何信息在越狱设备上是安全的。攻击者可以拿到Plist文件,导出整个keychain,替换方法实现,而且攻击者能作他想作的任何事情。不过开发者可以使用一些小技巧来使得脚本小子从应用得到信息变得更难。好比把文件加密放到本地设备上。这里这篇文章详细的讨论了这一点。或者你能够使得攻击者更难理解你的信息。好比考虑要把某个用户的认证令牌(authentication token)保存到keychain当中,脚本小子可能就会导出keychain中的这个数据,而后试图劫持用户的会话。咱们只需再把这个认证令牌字符串反转一下(reverse),而后再保存到keychain中,那么攻击者就不太可能会知道认证令牌是反转保存的。固然,攻击者能够追踪你的应用的每个调用,而后理解到这一点,可是,一个如此简单的技术就可以让脚本小子猜足够的时间,以致于他们会开始寻找其它应用的漏洞。另外一个简单技巧就是在每一个真正的值保存以前都追加一个常量字符串

  在接下来的文章里,咱们将讨论使用GDB进行运行时分析。 

 

译  者: MysticCoder
关于做者:专一于iOS项目开发。若有问题或建议,请多多赐教!
版权声明:本文版权归做者和博客园共有,欢迎转载,但未经做者赞成必须保留此段声明,且在文章页面明显位置给出原文连接。
特此声明:全部评论和私信都会在第一时间回复。也欢迎园子的大大们指正错误,共同进步。或者 直接私信
声援博主:若是您以为文章对您有帮助,能够点击文章右下角 【推荐】一下。您的鼓励是做者坚持原创和持续写做的最大动力!
相关文章
相关标签/搜索