iOS APP之本地數(shù)據(jù)存儲(譯)

最近工作中完成了項目的用戶信息本地存儲,查閱了一些本地存儲加密方法等相關(guān)資料。期間發(fā)現(xiàn)了一個來自印度理工學院(IIT)的信息安全工程師的個人博客,寫了大量有關(guān)iOS Application security的文章。
  個人感覺寫的還不錯,實用性比較強,加之閱讀難度不大,于是趁著工作日無聊之際,小翻譯了一篇。
   原文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/
真的不難,還是建議大家閱讀原文。OK,廢話不多說。上譯文:

iOS應用安全(20) - 本地數(shù)據(jù)存儲
-2013.10.26
-發(fā)表自Prateek Gianchandani

在這篇文章中,我們將要看看應用中存儲數(shù)據(jù)到本地的一些不同的方法以及這些方法的安全性。
  
我們將會在一個demo上這些這些測試,你可以從我的github賬號上下載這個例子程序。對于CoreData的例子,你可以從下載例子程序。本例有一個不同點就是我們將會在模擬器上運行這些應用,而不是在設備上運行。這樣做的目的是為了證明在前面文章中的操作都可以通過Xcode來把這些應用運行在模擬器上。當然,你也可以使用前面文章中的步驟把這應用安裝到設備上。

NSUserDefaults
  保存用戶信息和屬性的一個非常普通的方法就是使用NSUserDefaults。保存在NSUserDefaults中的信息在你的應用關(guān)閉后再次打開之后依然存在。保存信息到NSUserDefaults的一個例子就是保存用戶是否已登錄的狀態(tài)。我們把用戶的登錄狀態(tài)保存到NSUserDefaults以便用戶關(guān)閉應用再次打開應用的時候,應用能夠從NSUserDefaults獲取數(shù)據(jù),根據(jù)用戶是否登錄展示不同的界面。有些應用也用這個功能來保存機密數(shù)據(jù),比如用戶的訪問令牌,以便下次應用登錄的時候,它們能夠使用這個令牌來再次認證用戶。
  從我的github可以下載例子應用,運行起來。你可以得到下面的界面,現(xiàn)在輸入一些信息到與NSUserDefaults相關(guān)的文本框,然后點擊下面的“Save in NSUserDefaults”。這樣數(shù)據(jù)就保存到NSUserDefaults了。


  許多人不知道的是保存到NSUserDefaults的數(shù)據(jù)并沒有加密,因此可以很容易的從應用的包中看到。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保存的數(shù)據(jù)都可以在如下圖所示的Library -> Preferences -> $AppBundleId.plist文件中找到。

  打開這個plist文件,我們可以清楚的看到這個文件的內(nèi)容。

  有時候,plist文件會以二進制格式保存,因此可能第一下看到會覺得不可讀。你可以用plutil工具把它轉(zhuǎn)成xml格式,或者直接用iExplorer在設備上查看。

Plist 文件
  另一種保存數(shù)據(jù)普遍用的方法就是plist文件。Plist文件應該始終被用來保存那些非機密的文件,因為它們沒有加密,因此即使在非越獄的設備上也非常容易被獲取。已經(jīng)有漏洞被爆出來,大公司把機密數(shù)據(jù)比如訪問令牌,用戶名和密碼保存到plist文件中。在下面的demo中,我們輸入一些信息并保存到plist文件。


  下面是把數(shù)據(jù)保存到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內(nèi)部使用Sqlite來保存信息,因此我們這里將只會介紹下CoreData。如果你不知道什么是CoreData,下面是從蘋果文檔介紹CoreData截的圖。


  因此,基本上,CoreData可以用來創(chuàng)建一個model,管理不同對象的關(guān)系,把數(shù)據(jù)保存到本地,然后當你查詢的時候從本地緩存中獲取它們。本例中,我們將使用一個demo,位于github。運行起來,你會發(fā)現(xiàn)它只是一個簡單的RSS feed。

  這個應用用CoreData保存數(shù)據(jù)。一個非常重要的一點就是CoreData內(nèi)部使用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的狀態(tài)是on。

  正如我們看到的那樣,默認的,保存在CoreData的數(shù)據(jù)都是沒有加密的,因此可以輕易的被取出。因此,我們不應該用 CoreData保存機密數(shù)據(jù)。 有些庫包裝了一下CoreData, 聲稱能夠保存加密數(shù)據(jù)。也有些庫能夠把數(shù)據(jù)加密保存到設備上,不過不使用CoreData。例如,Salesforce Mobile SDK 就使用了一個被稱為SmartStore的功能來把加密數(shù)據(jù)以"Soups"的形式保存到設備上。

Keychain
  有些開發(fā)者不太喜歡把數(shù)據(jù)保存到Keychain中,因為實現(xiàn)起來不那么直觀。不過,把信息保存到Keychain中可能是非越獄設備上最安全的一種保存數(shù)據(jù)的方式了而在越獄設備上,沒有任何事情是安全的。這篇文章展示了使用一個簡單的wrapper類,把數(shù)據(jù)保存到keychain是多么的簡單。使用這個wrapper來保存數(shù)據(jù)到keychain就像把數(shù)據(jù)保存到NSUserDefaults那么簡單。下面就是一段把字符串保存到keychain的代碼。請注意和使用NSUserDefaults的語法非常類似。

PDKeychainBindings *bindings = [PDKeychainBindings sharedKeychainBindings];
[bindings setObject:@"XYZ" forKey:@"authToken"];

下面是一段從keychain中取數(shù)據(jù)的代碼。

PDKeychainBindings *bindings = [PDKeychainBindings sharedKeychainBindings];
NSLog(@"Auth token is %@",[bindings objectForKey:@"authToken"]]);

一些小技巧
  正如之前討論過的那樣,沒有任何信息在越獄設備上是安全的。攻擊者能夠拿到Plist文件,導出整個keychain,替換方法實現(xiàn),并且攻擊者能做他想做的任何事情。不過開發(fā)者能夠使用一些小技巧來使得腳本小子從應用獲得信息變得更難。比如把文件加密放到本地設備上。這里這篇文章詳細的討論了這一點?;蛘吣憧梢?strong>使得攻擊者更難理解你的信息。比如考慮要把某個用戶的認證令牌(authentication token)保存到keychain當中,腳本小子可能就會導出keychain中的這個數(shù)據(jù),然后試圖劫持用戶的會話。我們只需再把這個認證令牌字符串反轉(zhuǎn)一下(reverse),然后再保存到keychain中,那么攻擊者就不太可能會知道認證令牌是反轉(zhuǎn)保存的。當然,攻擊者可以追蹤你的應用的每一個調(diào)用,然后理解到這一點,但是,一個如此簡單的技術(shù)就能夠讓腳本小子猜足夠的時間,以至于他們會開始尋找其它應用的漏洞。另一個簡單技巧就是在每個真正的值保存之前都追加一個常量字符串。
  在接下來的文章里,我們將討論使用GDB進行運行時分析。

譯  者:MysticCoder
出  處:http://www.cnblogs.com/mysticCoder/
關(guān)于作者:專注于iOS項目開發(fā)。如有問題或建議,請多多賜教!
版權(quán)聲明:本文版權(quán)歸作者和博客園共有,歡迎轉(zhuǎn)載,但未經(jīng)作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文鏈接。
特此聲明:所有評論和私信都會在第一時間回復。也歡迎園子的大大們指正錯誤,共同進步?;蛘咧苯铀叫盼?/p>

聲援博主:如果您覺得文章對您有幫助,可以點擊文章右下角【推薦】一下。您的鼓勵是作者堅持原創(chuàng)和持續(xù)寫作的最大動力!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關(guān)閱讀更多精彩內(nèi)容

  • keychain app官方鏈接 重要的事情說三遍 使用keychain group的時候,測試一定要使用真機! ...
    Rxiaobing閱讀 3,358評論 1 5
  • 數(shù)據(jù)存儲 sqlite中插入特殊字符的方法和接收到處理方法。 除’其他的都是在特殊字符前面加“/”,而 ' -> ...
    b485c88ab697閱讀 7,459評論 2 32
  • 這個世界上有關(guān)于青春的迷茫誰都有過,這不我也來了…… 這兩天被兩個問題困擾一個是有關(guān)于獨立,一個是有關(guān)于興趣。無論...
    小張張大皮皮閱讀 198評論 0 0
  • 我們對那些高大的宏偉的東西 習慣性的會肅然起敬 但其實我們並不知道自己在尊敬什麼
    憨憨爹閱讀 130評論 0 0
  • 我一直喜歡的一本雜志 青春美文里有一個欄目是 微微道來。 一直是 那一個女子在寫。我很喜歡她的文字。后來關(guān)注...
    水弋月閱讀 310評論 0 2

友情鏈接更多精彩內(nèi)容