版本記錄
版本號 | 時間 |
---|---|
V1.0 | 2017.08.29 |
前言
在這個信息爆炸的年代,特別是一些敏感的行業(yè),比如金融業(yè)和銀行卡相關(guān)等等,這都對
app
的安全機制有更高的需求,很多大公司都有安全 部門,用于檢測自己產(chǎn)品的安全性,但是及時是這樣,安全問題仍然被不斷曝出,接下來幾篇我們主要說一下app
的安全機制。感興趣的看我上面幾篇。
1. APP安全機制(一)—— 幾種和安全性有關(guān)的情況
2. APP安全機制(二)—— 使用Reveal查看任意APP的UI
3. APP安全機制(三)—— Base64加密
4. APP安全機制(四)—— MD5加密
5. APP安全機制(五)—— 對稱加密
6. APP安全機制(六)—— 非對稱加密
7. APP安全機制(七)—— SHA加密
偏好設(shè)置存儲信息的隱患
大家都知道,存儲可以有很多種方式,其中一種就是偏好設(shè)置進(jìn)行存儲,但是在存儲之前如果不進(jìn)行任何加密的話,那么黑客只要是將沙盒攻陷獲取里面的信息,你的數(shù)據(jù)就裸奔了,你的敏感數(shù)據(jù)就一覽無余了,所以在偏好設(shè)置里面存儲信息時最好進(jìn)行加密存儲。
有關(guān)偏好設(shè)置加密的一個框架
關(guān)于偏好設(shè)置加密,大家可以用自己的方法進(jìn)行加密,還可以做的就是用第三方加密框架,這里要說的就是NSUserDefaults
的一個分類SecureAdditions
,大家可以用pod進(jìn)行安裝,如下所示:
pod 'SecureNSUserDefaults'
1. SecureAdditions API
下面我們就看一下該分類或者說框架的API接口。
1. NSUserDefaults+SecureAdditions.h
#import <Foundation/Foundation.h>
@interface NSUserDefaults (SecureAdditions)
- (void)setSecret:(NSString*)secret;
- (BOOL)secretBoolForKey:(NSString *)defaultName;
- (NSData*)secretDataForKey:(NSString *)defaultName;
- (NSDictionary*)secretDictionaryForKey:(NSString *)defaultName;
- (float)secretFloatForKey:(NSString *)defaultName;
- (NSInteger)secretIntegerForKey:(NSString *)defaultName;
- (NSArray *)secretStringArrayForKey:(NSString *)defaultName;
- (NSString *)secretStringForKey:(NSString *)defaultName;
- (double)secretDoubleForKey:(NSString *)defaultName;
- (NSURL*)secretURLForKey:(NSString *)defaultName;
- (id)secretObjectForKey:(NSString *)defaultName;
- (void)setSecretBool:(BOOL)value forKey:(NSString *)defaultName;
- (void)setSecretFloat:(float)value forKey:(NSString *)defaultName;
- (void)setSecretInteger:(NSInteger)value forKey:(NSString *)defaultName;
- (void)setSecretDouble:(double)value forKey:(NSString *)defaultName;
- (void)setSecretURL:(NSURL *)url forKey:(NSString *)defaultName;
- (void)setSecretObject:(id)value forKey:(NSString *)defaultName;
@end
2. NSUserDefaults+SecureAdditions.m
#import "NSUserDefaults+SecureAdditions.h"
#import "CocoaSecurity.h"
#define kStoredObjectKey @"storedObject"
@implementation NSUserDefaults (SecureAdditions)
static NSString *_secret = nil;
#pragma mark - Getter methods
- (BOOL)secretBoolForKey:(NSString *)defaultName
{
id object = [self secretObjectForKey:defaultName];
if([object isKindOfClass:[NSNumber class]]) {
return [object boolValue];
} else {
return NO;
}
}
- (NSData*)secretDataForKey:(NSString *)defaultName
{
id object = [self secretObjectForKey:defaultName];
if([object isKindOfClass:[NSData class]]) {
return object;
} else {
return nil;
}
}
- (NSDictionary*)secretDictionaryForKey:(NSString *)defaultName
{
id object = [self secretObjectForKey:defaultName];
if([object isKindOfClass:[NSDictionary class]]) {
return object;
} else {
return nil;
}
}
- (float)secretFloatForKey:(NSString *)defaultName
{
id object = [self secretObjectForKey:defaultName];
if([object isKindOfClass:[NSNumber class]]) {
return [object floatValue];
} else {
return 0.f;
}
}
- (NSInteger)secretIntegerForKey:(NSString *)defaultName
{
id object = [self secretObjectForKey:defaultName];
if([object isKindOfClass:[NSNumber class]]) {
return [object integerValue];
} else {
return 0;
}
}
- (NSArray *)secretStringArrayForKey:(NSString *)defaultName
{
id objects = [self secretObjectForKey:defaultName];
if([objects isKindOfClass:[NSArray class]]) {
for(id object in objects) {
if(![object isKindOfClass:[NSString class]]) {
return nil;
}
}
return objects;
} else {
return nil;
}
}
- (NSString *)secretStringForKey:(NSString *)defaultName
{
id object = [self secretObjectForKey:defaultName];
if([object isKindOfClass:[NSString class]]) {
return object;
} else {
return nil;
}
}
- (double)secretDoubleForKey:(NSString *)defaultName
{
id object = [self secretObjectForKey:defaultName];
if([object isKindOfClass:[NSNumber class]]) {
return [object doubleValue];
} else {
return 0;
}
}
- (NSURL*)secretURLForKey:(NSString *)defaultName
{
id object = [self secretObjectForKey:defaultName];
if([object isKindOfClass:[NSURL class]]) {
return object;
} else {
return nil;
}
}
- (id)secretObjectForKey:(NSString *)defaultName
{
// Check if we have a (valid) key needed to decrypt
NSAssert(_secret, @"Secret may not be nil when storing an object securely");
// Fetch data from user defaults
NSData *data = [self objectForKey:defaultName];
// Check if we have some data to decrypt, return nil if no
if(data == nil) {
return nil;
}
// Try to decrypt data
@try {
// Generate key and IV
CocoaSecurityResult *keyData = [CocoaSecurity sha384:_secret];
NSData *aesKey = [keyData.data subdataWithRange:NSMakeRange(0, 32)];
NSData *aesIv = [keyData.data subdataWithRange:NSMakeRange(32, 16)];
// Decrypt data
CocoaSecurityResult *result = [CocoaSecurity aesDecryptWithData:data key:aesKey iv:aesIv];
// Turn data into object and return
NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:result.data];
id object = [unarchiver decodeObjectForKey:kStoredObjectKey];
[unarchiver finishDecoding];
return object;
}
@catch (NSException *exception) {
// Whoops!
NSLog(@"Cannot receive object from encrypted data storage: %@", exception.reason);
return nil;
}
@finally {}
}
#pragma mark - Setter methods
- (void)setSecret:(NSString*)secret
{
_secret = secret;
}
- (void)setSecretBool:(BOOL)value forKey:(NSString *)defaultName
{
[self setSecretObject:[NSNumber numberWithBool:value] forKey:defaultName];
}
- (void)setSecretFloat:(float)value forKey:(NSString *)defaultName
{
[self setSecretObject:[NSNumber numberWithFloat:value] forKey:defaultName];
}
- (void)setSecretInteger:(NSInteger)value forKey:(NSString *)defaultName
{
[self setSecretObject:[NSNumber numberWithInteger:value] forKey:defaultName];
}
- (void)setSecretDouble:(double)value forKey:(NSString *)defaultName
{
[self setSecretObject:[NSNumber numberWithDouble:value] forKey:defaultName];
}
- (void)setSecretURL:(NSURL *)url forKey:(NSString *)defaultName
{
[self setSecretObject:url forKey:defaultName];
}
- (void)setSecretObject:(id)value forKey:(NSString *)defaultName
{
// Check if we have a (valid) key needed to encrypt
NSAssert(_secret, @"Secret may not be nil when storing an object securely");
@try {
// Create data object from dictionary
NSMutableData *data = [[NSMutableData alloc] init];
NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data];
[archiver encodeObject:value forKey:kStoredObjectKey];
[archiver finishEncoding];
// Generate key and IV
CocoaSecurityResult *keyData = [CocoaSecurity sha384:_secret];
NSData *aesKey = [keyData.data subdataWithRange:NSMakeRange(0, 32)];
NSData *aesIv = [keyData.data subdataWithRange:NSMakeRange(32, 16)];
// Encrypt data
CocoaSecurityResult *result = [CocoaSecurity aesEncryptWithData:data key:aesKey iv:aesIv];
// Save data in user defaults
[self setObject:result.data forKey:defaultName];
}
@catch (NSException *exception) {
// Whoops!
NSLog(@"Cannot store object securely: %@", exception.reason);
}
@finally {}
}
@end
大家看代碼,可以看見里面使用的就是AES
對稱加密的方法。
加密框架的使用
下面我就舉一個很小的例子,為大家說一下加密框架的使用。
#import <SecureNSUserDefaults/NSUserDefaults+SecureAdditions.h>
//該類方法的作用就是保存數(shù)據(jù),里面就用到了這個框架
+ (void)saveProfile:(JJUserInfo *)userInfo
{
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
[userDefaults setSecret:secretString];
NSMutableDictionary *userDict = [[NSMutableDictionary alloc] init];
[userDict setObject:userInfo.userId?:@"" forKey:kUid];
[userDict setObject:userInfo.token?:@"" forKey:kToken];
[userDict setObject:userInfo.nickname?:@"" forKey:kUser_nickname];
[userDict setObject:userInfo.avatar?:@"" forKey:kAvater];
[userDict setObject:userInfo.coin?:@"" forKey:kCoin];
[userDict setObject:userInfo.balance?:@"" forKey:kBalance];
[userDict setObject:userInfo.isArtist?:@"" forKey:kUserType];
[userDict setObject:userInfo.easePasswordStr?:@"" forKey:kEasePassword];
[userDefaults setSecretObject:userDict.copy forKey:userData];
[userDefaults synchronize];
}
后記
關(guān)于APP安全是一個無法完結(jié)的話題,隨著技術(shù)的深入,破解與反破解的技術(shù)進(jìn)行一輪輪的博弈,所以未完,待續(xù)~~~~