一.本地数据安全规范
1.本地存储密码、敏感数据加密:
本地存储:NSUserDefaults存储、plist文件存储、归档存储、CoreData存储时候,不能存储明文密码和敏感数据(如:用户手机号、姓名、邮箱、身份证、银行卡等敏感信息)。
原因:
iTunes会备份应用Documents目录,越狱手机通过iTools工具等可以直接查看应用的Documents、Library/Caches、Tmp及其他所有目录存储信息,而这些存储都在这些目录下。
错误示范:
[data setObject:_userNameTF.text forKey:@"username"];
[data setObject:_passwordTF.text forKey:@"password"];
正确示范:
[data setObject:[AES encode:_userNameTF.text] forKey:@"username"];
[data setObject:[AES encode:_passwordTF.text] forKey:@"password"];
2. 数据库存储:
使用数据库存储,需要对密码敏感数据等加密,或者整库加密
原因:
数据库,一般存储在Documents路径下的特殊文件,格式一般为.db或者.sqlite,导出后使用特殊工具即可查看如DB Browser for sqlite 和 SQLiteStudio。
正确示例
// 对数据库进行加密 SAFE_KEY: 为打开数据库密码
sqlite_key(db, SAFE_KEY.cString(using: String.Encoding.utf8), Int32(SAFE_KEY.characters.count))
3. keychain存储:
keychain的密码、证书、密钥、数字身份等存储必须加密存储
原因
Keychain的数据库内容使用了设备唯一的硬件密钥进行加密,该硬件密钥无法从设备上导出,存储内容比上面两个安全很多,但是攻击者还是可以通过越狱该设备,以及一些步骤读取到keychain里明文信息。
错误示例
+(void)saveUserName:(NSString *)userName andSavePassWord:(NSString *)password
{
NSMutableDictionary *usernamepasswordKVPairs = [[NSMutableDictionary alloc] initWithCapacity:42];
[usernamepasswordKVPairs setObject:password forKey:KEY_PASSWORD];
[usernamepasswordKVPairs setObject:userName forKey:KEY_USERNAME];
[CJFKeychain save:KEY_IN_KEYCHAIN data:usernamepasswordKVPairs];
}
正确示例
+(void)saveUserName:(NSString *)userName andSavePassWord:(NSString *)password
{
NSMutableDictionary *usernamepasswordKVPairs = [[NSMutableDictionary alloc] initWithCapacity:42];
[usernamepasswordKVPairs setObject:[AES encode:password] forKey:KEY_PASSWORD];
[usernamepasswordKVPairs setObject:[AES encode:userName] forKey:KEY_USERNAME];
[CJFKeychain save:KEY_IN_KEYCHAIN data:usernamepasswordKVPairs];
}
4.剪切板:
在使用剪切板的时候,使用应用级剪切板,在应用退出时候清空剪切板。
错误示例
// 获取系统级别的剪切板,保存在系统文件内,应用间共享
-(void)realyCopy() {
pasteboard = [UIPasteboard generalPasteboard];
[pasteboard setString:@"复制的字符串内容"];
}
正确示例
// 自定义的剪切板,在应用内共享,退出程序后就会被清除
-(void)realyCopy() {
pasteboard = [UIPasteboard pasteboardWithName:@"test" create: YES];
[pasteboard setString:@"复制的字符串内容"];
}
// 获取一个应用级别的剪切板,相当于自定义的剪切板,只是name为空,在应用内共享,退出程序后就会被清除
-(void)realyCopy() {
pasteboard = [UIPasteboard pasteboardWithUniqueName];
[pasteboard setString:@"复制的字符串内容"];
}
5. 系统键盘
①禁用了自动纠正功能的文本框:设置UITextView/UITextField 属性autocorrectionType 为. no类型 。
②密码输入框被一定要设置为密码输入类型:设置UITextView/UITextField 属性isSecureTextEntry为true。
③手机号、金钱输入框设置为数字键盘:设置UITextView/UITextField属性 keyboardType为数字键盘。
④还有些敏感的信息输入以上无法满足:自定义键盘。
6.应用进入后台时高斯模糊:
应用在进入后台挂起时,Window层增加一层高斯模糊,或添加一个遮挡页面。
原因:
当应用进入后台时,系统会自动在当前应用的页面截屏并存储到手机内,如果当前页面涉及敏感信息时,被攻击会造成泄密。如下图生成的两张图片路径:
二.HTTPS
所有网络请求都用SSL/TLS加密传输,即HTTPS和WSS等。
在使用AFNetworking网络框架,必须配置证书验证,避免中间人伪造攻击。所以我们必须使用AFSSLPinningModeCertificate对证书进行完整校验。
三.UIWebView漏洞
-
XSS漏洞
①、对输入框内的数据进行关键词过滤(如“script”字符串),避免输入恶意脚本语言。
②、在加载网页的内容之前,会用dataWithContentsOfURL方法将加载的网页的内容提取出来放入NSData中,在使用loadHTMLString之前可以对NSData的内容过滤,编码等等。
示例
- (void)test {
NSString *urlStr = @"https://www.baidu.com";
NSURL *url = [NSURL URLWithString:urlStr];
NSData *data = [NSData dataWithContentsOfURL:url];
NSString *htmlStr = [[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] stringByReplacingOccurrencesOfString:@"script" withString:@""];
}
四.Xcode
-
开发人员必须从App Store下载安装Xcode,或者从apple官网下载:https://developer.apple.com/download/more
原因:
2015年的xcode后门事件,原因就是从非官方渠道下载的xcode,被导入恶意代码会上传产品自身的部分基本信息,包括安装时间、应用id,应用名称、系统版本以及国家和语言等。
五.逆向工程反编译APP
-
你想反编译防止:
①、所有使用密码、敏感信息字符串地方都为密文,调用方法解密使用,不能直接明文存储。
②、编译构建时,对类名、方法名做混淆替换。
③、加固:使用第三方安全SDK来解决以上问题(网易盾、几维安全等)。
六.检测越狱和反调试
- 检测越狱:
①、判断是否存在越狱文件
/Applications/Cydia.app
/Library/MobileSubstrate/MobileSubstrate.dylib
/bin/bash
/usr/sbin/sshd
/etc/apt
②、判断cydia的URL scheme
- (BOOL)isOpenCydia{
return [[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:@"cydia://"]];
}
③、检测到越狱状态时候,禁止网络访问,清除本地缓存数据、数据库数据等。
-
反调试
使用
和 库来阻止GDB依附,从而达到阻止攻击者破解代码后,对我们的程序进行调试
#import
#import
typedef int (*ptrace_ptr_t)(int _request, pid_t _pid, caddr_t _addr, int _data);
#if !defined(PT_DENY_ATTACH)
#define PT_DENY_ATTACH 31
#endif // !defined(PT_DENY_ATTACH)
void disable_gdb() {
void* handle = dlopen(0, RTLD_GLOBAL | RTLD_NOW);
ptrace_ptr_t ptrace_ptr = dlsym(handle, "ptrace");
ptrace_ptr(PT_DENY_ATTACH, 0, 0, 0);
dlclose(handle);
}
int main(int argc, charchar *argv[])
{
#ifndef DEBUG
disable_gdb();
#endif
@autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([WQMainPageAppDelegate class]));
}
}