現在很多人對於安全越來越重視,作為程式猿的我們,也需要在這一方面多下功夫,讓我們APP使用者儲存的私人資訊更加的安全,我看到過很多的人寫程式碼,雖然明文密碼不會被儲存,經常是儲存伺服器返回的一個祕鑰,大部分程式猿就裸存了,直接就儲存在NSUserDefaults裡面了,也有些程式猿有對其進行AES或DES加密後再儲存,但是其本身AES或DES的祕鑰都是寫在程式碼中的,一旦程式被反編譯,想要獲取的祕鑰也是相當容易的一件事了。
蘋果自己本身就有一個方法可以讓我們儲存一些機密的東西,儲存的機制就是將我們需要儲存的東西儲存在鑰匙串?裡面,這樣除非整個iOS的安全機制被破解,要不然你儲存的東西就會相對的安全。
好了廢話不多少,下面的程式碼是最近我整理的一個儲存一些私人資訊的類,希望大家不吝賜教。
.h檔案
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
#import <Foundation/Foundation.h> @interface KeychainTool : NSObject /** * 儲存字串到?鑰匙串 * * @param sValue 對應的Value * @param sKey 對應的Key */ + (void)saveKeychainValue:(NSString *)sValue Key:(NSString *)sKey; /** * 從?鑰匙串獲取字串 * * @param sKey 對應的Key * * @return 返回儲存的Value */ + (NSString *)readKeychainValue:(NSString *)sKey; /** * 從?鑰匙串刪除字串 * * @param sKey 對應的Key */ + (void)deleteKeychainValue:(NSString *)sKey; @end |
.m 檔案
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
#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)saveKeychainValue:(NSString *)sValue Key:(NSString *)sKey { //Get search dictionary NSMutableDictionary *keychainQuery = [self getKeychainQuery:sKey]; //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:sValue] forKey:(__bridge_transfer id)kSecValueData]; //Add item to keychain with the search dictionary SecItemAdd((__bridge_retained CFDictionaryRef)keychainQuery, NULL); } + (NSString *)readKeychainValue:(NSString *)sKey { NSString *ret = nil; NSMutableDictionary *keychainQuery = [self getKeychainQuery:sKey]; //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) { <a href="http://www.jobbole.com/members/xyz937134366">@try</a> { ret = (NSString *)[NSKeyedUnarchiver unarchiveObjectWithData:(__bridge_transfer NSData *)keyData]; } <a href="http://www.jobbole.com/members/wx895846013">@catch</a> (NSException *e) { NSLog(@"Unarchive of %@ failed: %@", sKey, e); } <a href="http://www.jobbole.com/members/finally">@finally</a> { } } return ret; } + (void)deleteKeychainValue:(NSString *)sKey { NSMutableDictionary *keychainQuery = [self getKeychainQuery:sKey]; SecItemDelete((__bridge_retained CFDictionaryRef)keychainQuery); } @end |
最近這幾天我會將程式碼放到Git上去。