DearMiku

iOS安全 -- 数据安全

字数统计: 1.8k阅读时长: 6 min
2017/11/18 Share

概述

在正常的iOS系统下,由于沙盒与随机地址的分配的作用下,应用数据的安全是没有问题的,但是在越狱情况下,应用间的数据是共享的,这就存在安全问题,同时也存在手机失窃,面临取证攻击(主要),所以我们在存储敏感数据时要格外小心.

防止数据泄露的方法

正式版禁用NSLog/Print

NSLog方法本质并非向控制台输出调试信息,而是向苹果系统日志(Apple System Log)中输出错误信息,官方解释为

服务器接收到的消息(被输入规则过滤后)会存放在数据仓库(data store)中,该API允许客户端创建查询并搜索消息数据仓库中满足条件的消息.

换句话说可以把NSLog看做printf和syslog的结合体,在调试时将消息发送到Xcode控制台,在设备上运行时将消息发送到系统全局日志.而且此数据外界很容易获得,只需要从Xocde Window->Devices and Simulator 中就可以获得,例如我运行如下代码:

1
2
3
for (int i = 0; i<100; i++) {
NSLog(@"hahhahahahahahahahaha");
}

查看日志:

日志

所以在正式版中一定要禁用NSLog,以免意外.

HTTP缓存

URL加载系统会存储未加密的缓存数据,这些数据存储在Cache.db文件中.而这就会将一些敏感数据缓存在本地,导致不必要的安全风险.
这是一些清除缓存的API:

1
2
3
4
5
6
7
8
9
// 只会删除内存中的缓存
[[NSURLCache sharedURLCache] removeAllCachedResponses];

//限制缓存容量,然而该API并不能限制缓存,
//此配置只能在内存/硬盘空间不够时给系统发挥作用.
[[NSURLCache sharedURLCache] setDiskCapacity:0];

//设置Cache的缓存策略,并不能禁用缓存,而是在下次请求中不再使用缓存而已
manager.requestSerializer.cachePolicy = NSURLRequestReloadIgnoringLocalCacheData;

当我将上面三个方法都实现后,利用AFNetworking访问 https://www.baidu.com 时在沙盒中仍然有缓存的.

缓存
可以看到还是有缓存滴~ 那么该怎么办嘞~

取消缓存的方法

1,服务器返回响应头禁用缓存,Cache-Control: no-cache,no-store,must-revalidate
2,直接在Cache路径中 将缓存文件删除(粗暴有效)

截屏泄露

用户主动截屏并不是我要讨论的,我们可以在关键界面截屏后提示用户泄密风险(在iOS7后,只能在截屏后获得通知).
iOS会在应用进入后台之前对当前应用状态截屏,当重新打开应用时可以生成过度动画,提高用户体验,然而有时这就会泄露关键信息.

解决方案:

在屏幕被截取前对显示图像进行处理(如加上高斯模糊),在进入应用时将高斯模糊图去掉.

而”截屏”事件发生在应用进入后台之后.所以可以在- (void)applicationDidEnterBackground:(UIApplication *)application方法中实现高斯模糊操作.

钥匙串的使用

如果需要存储密码,个人资料等小段敏感数据,使用钥匙串最好不过了.我推荐使用 SSKeyChain库,它对钥匙串的操作进行了面向对象的封装.主要有以下几个方法:

可以将 服务与账号看成不同的文件夹, 服务是行号的上级目录

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 返回本应用的所有钥匙串信息
[SSKeychain allAccounts];

//发挥指定服务下的所有钥匙串信息
[SSKeychain accountsForService:<#(NSString *)#>];

//获取指定服务,账号的密码
[SSKeychain passwordForService:<#(NSString *)#> account:<#(NSString *)#>];

//删除指定服务,账户的信息
[SSKeychain deletePasswordForService:<#(NSString *)#> account:<#(NSString *)#>];

//将密码保存到指定服务,账号中
[SSKeychain setPassword:<#(NSString *)#> forService:<#(NSString *)#> account:<#(NSString *)#>];

除此之外,还要设置钥匙串的保护属性:

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
//设置钥匙串的保护属性,有以下几个选项
[SSKeychain setAccessibilityType:<#(CFTypeRef)#>];


//只有设备未被锁定时钥匙串就保持可用
extern const CFStringRef kSecAttrAccessibleWhenUnlocked
__OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_4_0);

//开机之后使用者第一次输入密码后钥匙可用(锁屏也可以)
extern const CFStringRef kSecAttrAccessibleAfterFirstUnlock
__OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_4_0);

//钥匙串在始终可用
extern const CFStringRef kSecAttrAccessibleAlways
__OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_4_0);

//只有设备设置密码才可用,且不可以移植到其他设备,一旦取消密码则存储信息会从设备中删除,且无备份(iOS8)
extern const CFStringRef kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly
__OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_8_0);

//只有设备未被锁定时钥匙串就保持可用,且不可移植
extern const CFStringRef kSecAttrAccessibleWhenUnlockedThisDeviceOnly
__OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_4_0);

//开机之后使用者第一次输入密码后钥匙可用(锁屏也可以),且不可移植
extern const CFStringRef kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly
__OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_4_0);

//钥匙串始终可用,且不可移植
extern const CFStringRef kSecAttrAccessibleAlwaysThisDeviceOnly
__OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_4_0);

注意:

即使删除应用,钥匙串中的信息并不会删除,只有恢复出厂设置才会删除.
keychain sharing可以进行钥匙串共享 是指同一家公司的同一个开发者账号开发的不同APP之间的钥匙串信息共享

数据保护API

苹果公司推出数据保护API,它允许开发者指定文件解密秘钥的生命周期.数据保护API使用用户密码和层级秘钥来加密保护文件的秘钥.作用上就像钥匙串那样保护文件.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//对options进行配置,设置文件保护级别
NSData* data = [NSData new];
[data writeToFile:@"" options:(NSDataWritingOptions) error:nil];


typedef NS_OPTIONS(NSUInteger, NSDataWritingOptions) {
NSDataWritingAtomic = 1UL << 0, // Hint to use auxiliary file when saving; equivalent to atomically:YES
NSDataWritingWithoutOverwriting API_AVAILABLE(macos(10.8), ios(6.0), watchos(2.0), tvos(9.0)) = 1UL << 1, // Hint to prevent overwriting an existing file. Cannot be combined with NSDataWritingAtomic.

NSDataWritingFileProtectionNone NS_ENUM_AVAILABLE_IOS(4_0) = 0x10000000,

//Comeplete是当前最安全的文件保护等级,锁屏之后文件会不可读.
NSDataWritingFileProtectionComplete NS_ENUM_AVAILABLE_IOS(4_0) = 0x20000000,

//如果文件被当前应用打开,那会暂时禁用该文件的保护,会确保该文件在锁屏时依旧可以写入.若想在锁屏之后再去打开则不可以.
NSDataWritingFileProtectionCompleteUnlessOpen NS_ENUM_AVAILABLE_IOS(5_0) = 0x30000000,
NSDataWritingFileProtectionCompleteUntilFirstUserAuthentication NS_ENUM_AVAILABLE_IOS(5_0) = 0x40000000,
NSDataWritingFileProtectionMask NS_ENUM_AVAILABLE_IOS(4_0) = 0xf0000000,

// Options with old names for NSData writing methods. Please stop using these old names.
NSAtomicWrite = NSDataWritingAtomic // Deprecated name for NSDataWritingAtomic
};

总结

从苹果提供的保护措施来看,它的保护措施几乎完全依赖于用户密码这个体系,使用钥匙串和数据保护其实就是在沙盒保护的基础上,又加了一层保护而已.
在越狱的情况,或者锁屏密码遭到暴力破解.那么安全就不保了,因此我感觉意义不是那么大.
所以我认为可以将钥匙串理解为一个高级沙盒, 它有删除软件数据保留,和钥匙串分享的功能.

以我个人见解,对于移动端数据安全这里我认为需要这样做:

1, 避免数据泄露(如HTTP缓存….);
2, 自己加密,即便是在钥匙串中的密码也是加密过多.这样想要盗窃用户数据不仅要攻克设备密码 也要攻克我们的软件 这样更加安全.

CATALOG
  1. 1. 概述
  2. 2. 防止数据泄露的方法
    1. 2.1. 正式版禁用NSLog/Print
    2. 2.2. HTTP缓存
      1. 2.2.1. 取消缓存的方法
    3. 2.3. 截屏泄露
    4. 2.4. 钥匙串的使用
    5. 2.5. 数据保护API
    6. 2.6. 总结