最近工做中完成了項目的用戶信息本地存儲,查閱了一些本地存儲加密方法等相關資料。期間發現了一個來自印度理工學院(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
-2013.10.26緩存
-發表自Prateek Gianchandani安全
在這篇文章中,咱們將要看看應用中存儲數據到本地的一些不一樣的方法以及這些方法的安全性。app
咱們將會在一個demo上這些這些測試,你能夠從個人github帳號上下載這個例子程序。對於CoreData的例子,你能夠從這下載例子程序。本例有一個不一樣點就是咱們將會在模擬器上運行這些應用,而不是在設備上運行。這樣作的目的是爲了證實在前面文章中的操做均可以經過Xcode來把這些應用運行在模擬器上。固然,你也可使用前面文章中的步驟把這應用安裝到設備上。ide
保存用戶信息和屬性的一個很是普通的方法就是使用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文件中。在下面的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。若是你不知道什麼是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中多是非越獄設備上最安全的一種保存數據的方式了。而在越獄設備上,沒有任何事情是安全的。這篇文章展 示了使用一個簡單的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進行運行時分析。