iOS本地數(shù)據(jù)存儲安全

NSUserDefaults不安全

NSUserDefaults其實是plist文件中鍵值存儲社牲,并且最大的問題是存在與沙盒中莺丑,這就對安全性埋下了隱患谴返。如果攻擊者破解app,拿到了沙盒中的數(shù)據(jù)命贴,就會造成數(shù)據(jù)泄漏道宅,后果不堪設(shè)想。

當然胸蛛,一般也不會有把密碼直接使用NSUserDefaults存儲的污茵,都會進行加密、或者是多重加密后再進行NSUserDefaults存儲葬项。這么做其實是可行的泞当,前提是加密算法不能泄漏。有個小問題就是玷室,如果用戶刪掉app重裝的話零蓉,之前所有存儲的敏感信息都會消失。比如穷缤,一個用戶誤刪了使用NSUserDefaults存儲密碼的app敌蜂,當重新安裝之后,由于以前是記住密碼免登錄津肛,只因為自己操作不當章喉,接下來要進入找回密碼功能,重新修改密碼才能再次使用app。這對用戶來說是一種相當不友好的體驗秸脱。

Plist不安全

什么是Plist文件落包?

屬性列表(Plist,Property List)是一種結(jié)構(gòu)化的二進制格式文件,包含了內(nèi)嵌鍵值對的可執(zhí)行bundle的基本配置信息摊唇。Plist文件主要用于存儲App的用戶設(shè)置及配置信息咐蝇,例如,游戲類App經(jīng)常會在Plist文件中存儲游戲等級和分數(shù)信息巷查。一般來說有序,App會將存儲用戶數(shù)據(jù)的Plist文件保存在“[App home目錄]/documents/”目錄下。Plist文件可以是XML格式或二進制格式岛请。

Plist文件有哪些安全風險旭寿?

Plist文件主要用于存儲用戶設(shè)置及App的配置信息,但App可能使用Plist文件存儲明文的用戶名崇败、密碼或其它一些個人敏感信息盅称。而保存在Plist文件中的二進制格式文件數(shù)據(jù)則可以使用Plist文件編輯器(如plutil)進行查看或修改,即使在一個沒有越獄的設(shè)備上后室,plist文件也可以通過工具iExplorer獲取缩膝。對于以編碼、未加密或弱加密形式存儲的敏感信息就可能會導致敏感信息泄露了咧擂。

相對比較安全的Keychain

Keychain是iOS所提供的一種安全存儲參數(shù)的方式逞盆,最常用來存儲賬號密碼松申,用戶信息銀行卡資料等信息俯逾,Keychain會以加密的方式存儲在設(shè)備中

Keychain 的結(jié)構(gòu)

Keychain內(nèi)部可以保存很多的信息贸桶。每條信息作為一個單獨的keychain item,keychain item一般為一個字典桌肴,每條keychain item包含一條data和很多attributes皇筛。舉個例子,一個用戶賬戶就是一條item坠七,用戶名可以作為一個attribute , 密碼就是data水醋。 keychain雖然是可以保存15000條item,每條50個attributes,但是蘋果工程師建議最好別放那么多彪置,存幾千條密碼拄踪,幾千字節(jié)沒什么問題。

如果把keychain item的類型指定為需要保護的類型比如password或者private key拳魁,item的data會被加密并且保護起來惶桐,如果把類型指定為不需要保護的類型,比如certificates,item的data就不會被加密姚糊。

extern CFTypeRef kSecClassGenericPassword
extern CFTypeRef kSecClassInternetPassword
extern CFTypeRef kSecClassCertificate
extern CFTypeRef kSecClassKey
extern CFTypeRef kSecClassIdentity OSX_AVAILABLE_STARTING(MAC_10_7, __IPHONE_2_0);
Keychain的特點
  • 數(shù)據(jù)并不是放在App的Sanbox贿衍,即使刪除了App,資料依然保存在keychain中救恨,如果重新安裝了App贸辈,還可以從keychain中獲取數(shù)據(jù)
  • keychain的數(shù)據(jù)可以用group的方式,讓程序可以在App間共享肠槽,不過需要相同的TeamD
  • keychain的數(shù)據(jù)是經(jīng)過加密的
Keychain的使用
  • 首先導入Security.framework 框架
  • Keychain的API提供以下幾個函數(shù)來操作Keychain
    • SecItemAdd 添加一個keychain item
    • SecItemUpdate 修改一個keychain item
    • SecItemCopyMatching 搜索一個keychain item
    • SecItemDelete 刪除一個keychain item
根據(jù)特定的Service創(chuàng)建一個用于操作KeyChain的Dictionary
- (NSMutableDictionary *)newSearchDictionary:(NSString *)identifier {
    NSMutableDictionary *searchDictionary = [[NSMutableDictionary alloc] init];
    //指定item的類型為GenericPassword
    [searchDictionary setObject:(id)kSecClassGenericPassword forKey:(id)kSecClass];
    
    //類型為GenericPassword的信息必須提供以下兩條屬性作為unique identifier
    [searchDictionary setObject:encodedIdentifier forKey:(id)kSecAttrAccount]裙椭;
    [searchDictionary setObject:encodedIdentifier forKey:(id)kSecAttrService];
    
    return searchDictionary;
}
- (BOOL)createKeychainValue:(NSString *)password forIdentifier:(NSString *)identifier {
    NSMutableDictionary *dictionary = [self newSearchDictionary:identifier];
    
    NSData *passwordData = [password dataUsingEncoding:NSUTF8StringEncoding];
    [dictionary setObject:passwordData forKey:(id)kSecValueData];
    
    OSStatus status = SecItemAdd((CFDictionaryRef)dictionary, NULL);
    [dictionary release];
    if (status == errSecSuccess) {
        return YES;
    }
    return NO;
}

- (void)deleteKeychainValue:(NSString *)identifier {
    NSMutableDictionary *searchDictionary = [self newSearchDictionary:identifier];
    SecItemDelete((CFDictionaryRef)searchDictionary);
}
- (BOOL)updateKeychainValue:(NSString *)password forIdentifier:(NSString *)identifier {
    NSMutableDictionary *searchDictionary = [self newSearchDictionary:identifier];
    
    NSMutableDictionary *updateDictionary = [[NSMutableDictionary alloc] init];
    NSData *passwordData = [password dataUsingEncoding:NSUTF8StringEncoding];
    [updateDictionary setObject:passwordData forKey:(id)kSecValueData];
    
    OSStatus status = SecItemUpdate((CFDictionaryRef)searchDictionary,
                                    (CFDictionaryRef)updateDictionary);
    
    [searchDictionary release];
    [updateDictionary release];
    
    if (status == errSecSuccess) {
        return YES;
    }
    return NO;
}
- (BOOL)createKeychainValue:(NSString *)password forIdentifier:(NSString *)identifier {
    NSMutableDictionary *dictionary = [self newSearchDictionary:identifier];
    
    NSData *passwordData = [password dataUsingEncoding:NSUTF8StringEncoding];
    [dictionary setObject:passwordData forKey:(id)kSecValueData];
    
    OSStatus status = SecItemAdd((CFDictionaryRef)dictionary, NULL);
    [dictionary release];
    if (status == errSecSuccess) {
        return YES;
    }
    return NO;
}
Keychain API的用法稍微有點復(fù)雜署浩。不過Apple自己也提供了一個封裝了Keychain API的類: KeychainItemWrapper

KeychainItemWrapper是apple官方例子“GenericKeychain”里一個訪問keychain常用操作的封裝類揉燃,在官網(wǎng)上下載了GenericKeychain項目后,只需要把“KeychainItemWrapper.h”和“KeychainItemWrapper.m”拷貝到我們項目筋栋,并導入Security.framework 炊汤。

KeychainItemWrapper的用法
/** 初始化一個保存用戶帳號的KeychainItemWrapper */
KeychainItemWrapper *wrapper = [[KeychainItemWrapper alloc] initWithIdentifier:@"Account Number"
                                                                   accessGroup:@"YOUR_APP_ID_HERE.com.yourcompany.AppIdentifier"];  
 
//保存帳號
[wrapper setObject:@"<帳號>" forKey:(id)kSecAttrAccount];    
 
//保存密碼
[wrapper setObject:@"<帳號密碼>" forKey:(id)kSecValueData];    
 
//從keychain里取出帳號密碼
NSString *password = [wrapper objectForKey:(id)kSecValueData];      
 
//清空設(shè)置
[wrapper resetKeychainItem];

其中方法“- (void)setObject:(id)inObject forKey:(id)key;”里參數(shù)“forKey”的值應(yīng)該是Security.framework 里頭文件“SecItem.h”里定義好的key,用其他字符串做key程序會崩潰弊攘!

網(wǎng)上也有許多大神封裝好的框架抢腐,我這里介紹兩個點星上千的框架
SFHFKeychainUtils
SAMKeychain

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市襟交,隨后出現(xiàn)的幾起案子迈倍,更是在濱河造成了極大的恐慌,老刑警劉巖捣域,帶你破解...
    沈念sama閱讀 222,252評論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件啼染,死亡現(xiàn)場離奇詭異,居然都是意外死亡焕梅,警方通過查閱死者的電腦和手機迹鹅,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,886評論 3 399
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來贞言,“玉大人斜棚,你說我怎么就攤上這事「么埃” “怎么了弟蚀?”我有些...
    開封第一講書人閱讀 168,814評論 0 361
  • 文/不壞的土叔 我叫張陵,是天一觀的道長酗失。 經(jīng)常有香客問我义钉,道長,這世上最難降的妖魔是什么级零? 我笑而不...
    開封第一講書人閱讀 59,869評論 1 299
  • 正文 為了忘掉前任断医,我火速辦了婚禮滞乙,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘鉴嗤。我一直安慰自己斩启,他們只是感情好,可當我...
    茶點故事閱讀 68,888評論 6 398
  • 文/花漫 我一把揭開白布醉锅。 她就那樣靜靜地躺著兔簇,像睡著了一般。 火紅的嫁衣襯著肌膚如雪硬耍。 梳的紋絲不亂的頭發(fā)上垄琐,一...
    開封第一講書人閱讀 52,475評論 1 312
  • 那天,我揣著相機與錄音经柴,去河邊找鬼狸窘。 笑死,一個胖子當著我的面吹牛坯认,可吹牛的內(nèi)容都是我干的翻擒。 我是一名探鬼主播,決...
    沈念sama閱讀 41,010評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼牛哺,長吁一口氣:“原來是場噩夢啊……” “哼陋气!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起引润,我...
    開封第一講書人閱讀 39,924評論 0 277
  • 序言:老撾萬榮一對情侶失蹤巩趁,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后淳附,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體议慰,經(jīng)...
    沈念sama閱讀 46,469評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,552評論 3 342
  • 正文 我和宋清朗相戀三年燃观,在試婚紗的時候發(fā)現(xiàn)自己被綠了褒脯。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,680評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡缆毁,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出到涂,到底是詐尸還是另有隱情脊框,我是刑警寧澤,帶...
    沈念sama閱讀 36,362評論 5 351
  • 正文 年R本政府宣布践啄,位于F島的核電站浇雹,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏屿讽。R本人自食惡果不足惜昭灵,卻給世界環(huán)境...
    茶點故事閱讀 42,037評論 3 335
  • 文/蒙蒙 一吠裆、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧烂完,春花似錦试疙、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,519評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至嘶窄,卻和暖如春怀跛,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背柄冲。 一陣腳步聲響...
    開封第一講書人閱讀 33,621評論 1 274
  • 我被黑心中介騙來泰國打工吻谋, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人现横。 一個月前我還...
    沈念sama閱讀 49,099評論 3 378
  • 正文 我出身青樓漓拾,卻偏偏與公主長得像,于是被迫代替她去往敵國和親长赞。 傳聞我的和親對象是個殘疾皇子晦攒,可洞房花燭夜當晚...
    茶點故事閱讀 45,691評論 2 361

推薦閱讀更多精彩內(nèi)容

  • keychain app官方鏈接 重要的事情說三遍 使用keychain group的時候,測試一定要使用真機得哆! ...
    Rxiaobing閱讀 3,209評論 1 5
  • 前言 在iOS開發(fā)中數(shù)據(jù)存儲的方式可以歸納為磁盤緩存和內(nèi)存緩存:磁盤緩存分為兩類:文件脯颜、數(shù)據(jù)庫存儲。 文件存儲:N...
    js丶閱讀 4,680評論 2 23
  • iOS安全攻與防 本地數(shù)據(jù)攻與防 https UIWebview 第三方sdk與xcode 反編譯與代碼混淆 越獄...
    天機否閱讀 10,647評論 8 66
  • 四月贩据,成都平原栋操,倒春寒才依依惜別,屬于春天的氣息又即將消散饱亮。雖然短暫矾芙,卻也讓人忍不住想出去走走,也只是瞥見林花謝了...
    姜戶川小白閱讀 112評論 0 0
  • 2017年9月17日近上,我是如是家人劉宛睿剔宪,種種子第28天。 發(fā)心:愿一切眾生能夠早日敢嘉蓿慧增長葱绒,成就圣果。愿我修身養(yǎng)...
    小Milk劉宛睿閱讀 202評論 0 4