iOS開發(fā)中用戶密碼應(yīng)該保存在哪里

版權(quán)聲明
本文由陳懷哲首發(fā)自簡書:http://www.reibang.com/users/9f2e536b78fd/latest_articles;
微信公眾號:陳懷哲(chenhuaizhe2016)听哭;
無需授權(quán)即可轉(zhuǎn)載却嗡,但請自覺保留以上版權(quán)聲明。


如果要實現(xiàn)自動登錄歌馍,不必每次打開應(yīng)用都去登錄,我們勢必要把密碼保存到本地湾碎。
一般我們的操作是:
每次打開應(yīng)用后尸闸,如果存在密碼,直接進(jìn)入界面兵拢,然后再進(jìn)行后臺密碼驗證翻斟。如果沒網(wǎng)絡(luò),我們可以跳過驗證说铃;如果有網(wǎng)絡(luò)访惜,我們可以后臺去驗證帳號密碼的正確性,并根據(jù)服務(wù)器的response做一些操作腻扇。

</br>

為什么直接把密碼存儲在NSUserDefaults中不安全债热?

</br>

iOS中沙盒有哪幾個文件夾,都是用來干嗎的

默認(rèn)情況下幼苛,每個沙盒含有3個文件夾:Documents, Library 和 tmp窒篱。因為應(yīng)用的沙盒機制,應(yīng)用只能在幾個目錄下讀寫文件

  • Documents:蘋果建議將程序中建立的或在程序中瀏覽到的文件數(shù)據(jù)保存在該目錄下舶沿,iTunes備份和恢復(fù)的時候會包括此目錄
  • Library:存儲程序的默認(rèn)設(shè)置或其它狀態(tài)信息墙杯;
  • Library/Caches:存放緩存文件,iTunes不會備份此目錄括荡,此目錄下文件不會在應(yīng)用退出刪除
  • tmp:提供一個即時創(chuàng)建臨時文件的地方高镐。

獲取到沙盒Library路徑

 //獲取Library目錄路徑
-  (void)getLibraryPath
 {
    NSArray * pathArray = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory,NSUserDomainMask, YES);
   NSString * libraryStrPath = [pathArray objectAtIndex:0];
    NSLog(@"LibraryPath:%@“,libraryStrPath);
 }

如圖就是NSUserDefaults對應(yīng)的plist文件在sandbox中的位置

藍(lán)色部分為plist文件

如果sandbox被破解,或者你的手機被越獄一汽,那么就能輕松拿到這個文件避消。
那么就能輕松讀到存儲的信息,密碼就會不安全:

在plist中可以找到密碼

這對于其它保存在NSUserDefaults中的信息也是一樣的召夹,所以對于存在NSUserDefaults中的東西岩喷,最好混淆加密一下再存儲。

如何刪除NSUserDefaults對應(yīng)的plist文件监憎?

其實就是刪除plist文件中所有的鍵值對纱意。

NSUserDefaults *userDefatluts = [NSUserDefaults standardUserDefaults];
NSDictionary *dictionary = [userDefaults dictionaryRepresentation];
for(NSString* key in [dictionary allKeys]){
     [userDefaults removeObjectForKey:key];
     [userDefaults synchronize];
}

</br>

如何解決“直接把密碼存儲在NSUserDefaults中不安全”的問題?

把密碼加密后再存儲到NSUserDefaults中

iOS中提供了很多種加密算法鲸阔,對于存儲密碼偷霉,可以使用不可逆的MD5加密迄委。
使用MD5加密需要導(dǎo)入頭文件:
''#import <CommonCrypto/CommonDigest.h>

##### 簡單的MD5加密
+ ( NSString *)md5String:( NSString *)str

{

const char *myPasswd = [str UTF8String ];

unsigned char mdc[ 16 ];

CC_MD5 (myPasswd, ( CC_LONG ) strlen (myPasswd), mdc);

NSMutableString *md5String = [ NSMutableString string ];

for ( int i = 0 ; i< 16 ; i++) {

[md5String appendFormat : @"%02x" ,mdc[i]];

}

return md5String;

}

##### 復(fù)雜一些的MD5加密
+ ( NSString *)md5String:( NSString *)str
 
 {
 
 const char *myPasswd = [str UTF8String ];
 
 unsigned char mdc[ 16 ];
 
 CC_MD5 (myPasswd, ( CC_LONG ) strlen (myPasswd), mdc);
 
 NSMutableString *md5String = [ NSMutableString string ];
 
 [md5String appendFormat : @"%02x" ,mdc[ 0 ]];
 
 for ( int i = 1 ; i< 16 ; i++) {
 
 [md5String appendFormat : @"%02x" ,mdc[i]^mdc[ 0 ]];

不使用NSUserDefaults保存密碼,使用keyChain來保存密碼

更加保險的方法是把密碼保存在iOS提供的keychina中类少,并且刪除應(yīng)用后叙身,密碼不會刪除,下載安裝還能使用硫狞。iOS系統(tǒng)提供了一些方法信轿,進(jìn)行一些簡單的封裝之后,就可以很方便的使用残吩。

封裝后可供使用的幾個類

Github-chenhuaizhe-iOS-keychain
你也可以在這里直接下載财忽,更多交流可以關(guān)注我的微博:@陳懷哲

下面是封裝代碼,使用時需要先導(dǎo)入Security.framework:

PassWordTool.h

#import <Foundation/Foundation.h>

@interface PassWordTool : NSObject
/**
 *    @brief    存儲密碼
 *
 *    @param     password     密碼內(nèi)容
 */
+(void)savePassWord:(NSString *)password;

/**
 *    @brief    讀取密碼
 *
 *    @return    密碼內(nèi)容
 */
+(id)readPassWord;

/**
 *    @brief    刪除密碼數(shù)據(jù)
 */
+(void)deletePassWord;

@end

PassWordTool.m

 import "PassWordTool.h"
 import "KeychainTool.h"
 
 @implementation PassWordTool
 static NSString * const KEY_IN_KEYCHAIN = @"com.chenyuan.app.userid";
 static NSString * const KEY_PASSWORD = @"com.chenyuan.app.password";
 
+(void)savePassWord:(NSString *)password
 {
     NSMutableDictionary *usernamepasswordKVPairs = [NSMutableDictionary dictionary];
     [usernamepasswordKVPairs setObject:password forKey:KEY_PASSWORD];
     [KeychainTool save:KEY_IN_KEYCHAIN data:usernamepasswordKVPairs];
 }
 
+(id)readPassWord
 {
     NSMutableDictionary *usernamepasswordKVPair = (NSMutableDictionary *)[KeychainTool load:KEY_IN_KEYCHAIN];
     return [usernamepasswordKVPair objectForKey:KEY_PASSWORD];
 }
 
+(void)deletePassWord
 {
     [KeychainTool delete:KEY_IN_KEYCHAIN];
 }
 @end

KeychainTool.h

#import <Foundation/Foundation.h>
 
@interface KeychainTool : NSObject
 
+ (NSMutableDictionary *)getKeychainQuery:(NSString *)service ;
 
+ (void)save:(NSString *)service data:(id)data ;
 
+ (id)load:(NSString *)service ;
 
+ (void)delete:(NSString *)service ;
 
@end

KeychainTool.m

import "KeychainTool.h"

@implementation KeychainTool

  • (NSMutableDictionary *)getKeychainQuery:(NSString *)service {
    return [NSMutableDictionary dictionaryWithObjectsAndKeys:
    (__bridge_transfer id)kSecClassGenericPassword,(__bridge_transfer id)kSecClass,
    service, (__bridge_transfer id)kSecAttrService,
    service, (__bridge_transfer id)kSecAttrAccount,
    (__bridge_transfer id)kSecAttrAccessibleAfterFirstUnlock,(__bridge_transfer id)kSecAttrAccessible,
    nil];
    }

  • (void)save:(NSString *)service data:(id)data {
    //Get search dictionary
    NSMutableDictionary *keychainQuery = [self getKeychainQuery:service];
    //Delete old item before add new item
    SecItemDelete((__bridge_retained CFDictionaryRef)keychainQuery);
    //Add new object to search dictionary(Attention:the data format)
    [keychainQuery setObject:[NSKeyedArchiver archivedDataWithRootObject:data] forKey:(__bridge_transfer id)kSecValueData];
    //Add item to keychain with the search dictionary
    SecItemAdd((__bridge_retained CFDictionaryRef)keychainQuery, NULL);
    }

  • (id)load:(NSString *)service {
    id ret = nil;
    NSMutableDictionary *keychainQuery = [self getKeychainQuery:service];
    //Configure the search setting
    [keychainQuery setObject:(id)kCFBooleanTrue forKey:(__bridge_transfer id)kSecReturnData];
    [keychainQuery setObject:(__bridge_transfer id)kSecMatchLimitOne forKey:(__bridge_transfer id)kSecMatchLimit];
    CFDataRef keyData = NULL;
    if (SecItemCopyMatching((__bridge_retained CFDictionaryRef)keychainQuery, (CFTypeRef *)&keyData) == noErr) {
    @try {
    ret = [NSKeyedUnarchiver unarchiveObjectWithData:(__bridge_transfer NSData *)keyData];
    } @catch (NSException *e) {
    NSLog(@"Unarchive of %@ failed: %@", service, e);
    } @finally {
    }
    }
    return ret;
    }

  • (void)delete:(NSString *)service {
    NSMutableDictionary *keychainQuery = [self getKeychainQuery:service];
    SecItemDelete((__bridge_retained CFDictionaryRef)keychainQuery);
    }
    @end

#### 服務(wù)器密碼驗證登錄請求
驗證請求時泣侮,最好是不直接把明文密碼包含在請求里面即彪。
可以根據(jù)一系列字符串生成MD5加密后的簽名,根據(jù)user-id 和 簽名來驗證登錄活尊。
比如:

NSString *sourceStr = [NSString stringWithFormat:@"attach=iOS&chartset=utf-8&format=json&partner=google&userid=%@&password=%@”,userid,password];
NSString *signStr = [NSString md5String:sourceStr];

這樣得到的signStr和userid再作為網(wǎng)絡(luò)請求的參數(shù)傳給服務(wù)器做驗證隶校。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市酬凳,隨后出現(xiàn)的幾起案子惠况,更是在濱河造成了極大的恐慌遭庶,老刑警劉巖宁仔,帶你破解...
    沈念sama閱讀 221,635評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異峦睡,居然都是意外死亡翎苫,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,543評論 3 399
  • 文/潘曉璐 我一進(jìn)店門榨了,熙熙樓的掌柜王于貴愁眉苦臉地迎上來煎谍,“玉大人,你說我怎么就攤上這事龙屉∧耪常” “怎么了?”我有些...
    開封第一講書人閱讀 168,083評論 0 360
  • 文/不壞的土叔 我叫張陵转捕,是天一觀的道長作岖。 經(jīng)常有香客問我,道長五芝,這世上最難降的妖魔是什么痘儡? 我笑而不...
    開封第一講書人閱讀 59,640評論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮枢步,結(jié)果婚禮上沉删,老公的妹妹穿的比我還像新娘渐尿。我一直安慰自己,他們只是感情好矾瑰,可當(dāng)我...
    茶點故事閱讀 68,640評論 6 397
  • 文/花漫 我一把揭開白布砖茸。 她就那樣靜靜地躺著,像睡著了一般殴穴。 火紅的嫁衣襯著肌膚如雪渔彰。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,262評論 1 308
  • 那天推正,我揣著相機與錄音恍涂,去河邊找鬼。 笑死植榕,一個胖子當(dāng)著我的面吹牛再沧,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播尊残,決...
    沈念sama閱讀 40,833評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼炒瘸,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了寝衫?” 一聲冷哼從身側(cè)響起顷扩,我...
    開封第一講書人閱讀 39,736評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎慰毅,沒想到半個月后隘截,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,280評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡汹胃,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,369評論 3 340
  • 正文 我和宋清朗相戀三年婶芭,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片着饥。...
    茶點故事閱讀 40,503評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡犀农,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出宰掉,到底是詐尸還是另有隱情呵哨,我是刑警寧澤,帶...
    沈念sama閱讀 36,185評論 5 350
  • 正文 年R本政府宣布轨奄,位于F島的核電站孟害,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏戚绕。R本人自食惡果不足惜纹坐,卻給世界環(huán)境...
    茶點故事閱讀 41,870評論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧耘子,春花似錦果漾、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,340評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至捍歪,卻和暖如春户辱,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背糙臼。 一陣腳步聲響...
    開封第一講書人閱讀 33,460評論 1 272
  • 我被黑心中介騙來泰國打工庐镐, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人变逃。 一個月前我還...
    沈念sama閱讀 48,909評論 3 376
  • 正文 我出身青樓必逆,卻偏偏與公主長得像,于是被迫代替她去往敵國和親揽乱。 傳聞我的和親對象是個殘疾皇子名眉,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,512評論 2 359

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

  • 最近搞環(huán)信聊天,需求是游客身份也可以進(jìn)行聊天凰棉,當(dāng)用戶注冊了我們的APP后也需要把游客身份切換過來進(jìn)行聊天损拢,首先我們...
    EncourageMan閱讀 1,966評論 2 3
  • 一、什么是Keychain 二撒犀、為什么使用Keychain而不是NSUserDefaults 開發(fā)者通常會希望能夠...
    此號停止使用閱讀 3,441評論 1 5
  • KeyChain是蘋果提供的一種安全的保存用戶名福压、密碼、證書的方式绘证,將敏感信息保存在keychain中后隧膏,這些信息...
    lichengjin閱讀 1,144評論 6 3
  • 一哗讥、深復(fù)制和淺復(fù)制的區(qū)別嚷那? 1、淺復(fù)制:只是復(fù)制了指向?qū)ο蟮闹羔樃松罚磧蓚€指針指向同一塊內(nèi)存單元魏宽!而不復(fù)制指向?qū)ο蟮?..
    iOS_Alex閱讀 1,387評論 1 27
  • 卷十九,漢紀(jì)十一决乎。時間公元前124年至公元前119年队询。主要故事有:漢匈之戰(zhàn)、劉安謀反构诚、衛(wèi)青霍去病蚌斩、休屠王降漢、桑弘...
    賈海昕閱讀 413評論 0 0