iOS开发安全 防反编译

现在公司做的金融类项目,对于安全和反欺诈要求比较高,之前对App安全只有部分涉及,在这个项目中系统化的对App安全防护做了一些工作.

一.网络安全
http网络请求不安全是大家都知道的,所以配合后端做https的升级是必要的.
另一方面就是防中间人攻击,中间人就是介于客户端和服务端中间,截获两端的信息进行篡改,对两端进行欺骗.
我们目前采用的方法是对于传输的参数进行验签和加密.先上代码吧.

/*
请求参数:
data : 接口需要的参数(如果加密的话使用AES的CBC加密方式 ,key为时间戳timestamp +秘钥SecretKey)
token :  除部分接口调用时还没用token之外,都要上传
sign:  除sign本身外所有参数加上秘钥SecretKey降序排序以key1=value1&key2=value2的形式拼接然后MD5
version :  版本号
timestamp :  时间戳(到毫秒,例如1559635536593)
appId : 包名
requestId  :  请求id    时间戳(到毫秒,例如1559635536593)拼接一个10000内的随机数,
encryptedStatus :    是否加密 字符串类型 0 不加密 1 加密
*/

// 数据结构 :
{
  "data" : {
 "参数key" : "值value"
"token" : “bc53e2667ee7cf78d4b6c7b5a9c81af51534844249"
  },
“sign”:  “”
  "version" : “1.0.1",
  "timestamp" : “1559635536593", 
  appId” : “com.fsdf.fdfdf”
“requestId” : “1559635536593567”
“encryptedStatus”:  "1"
}

/*
服务器响应数据
message  :  接口提示信息
encryptedStatus :  是否加密 字符串类型 0 不加密 1 加密
data  :  json数据
code  :  状态码
requestId : 请求id
*/
// 数据结构 :
{
"message" : "成功"
“encryptedStatus”: "0"
“data” : {
  },
 "code" : 0
"requestId": ""
}

如果对MD5和AES加密不了解的可以去百度,这里不多说了.这里主要解释几个要点.
1.网络请求data里的为接口的私有参数,data外的是共有参数,所有接口都要上传共有参数
2.sign是防篡改的,一般逻辑是对参数做一定的排序,然后通过不同的转换,最后通过 MD5输出统一长度的标识码,后端使用同样的逻辑去校验,这样保证信息传输过程中没有篡改
3.token是客户端登录后服务端返回的,每个用户有且只有一个token,token可以用来做登录时效和保证单端登录,服务端每个接口都需要校验token是否有效,无效的token直接以错误状态码返回.
4.requestId请求ID,主要是用来拦截延时请求和重复请求.
5.appId主要区分请求的来源方

二.日志
生产环境中不要输出日志,系统日志是可以查到的,一般使用宏定义就可以避免,或者使用DDLOG.例如

// 输出
#ifdef DEBUG
#define SSLog(format, ...) printf("class: <%p %s:(%d) > method: %s %s",self, [[[NSString stringWithUTF8String:__FILE__] lastPathComponent] UTF8String], __LINE__, __PRETTY_FUNCTION__, [[NSString stringWithFormat:(format), ##__VA_ARGS__] UTF8String] )
#else
#define SSLog(format, ...)
#endif

三.本地信息存储
本地信息存储就遵循一个原则,重要信息不能明文保存或者简单编码保存,不管是存在沙盒还是keychain中都是不安全的.我的解决方案是尽量将敏感信息存储于服务器端,使用时请求,使用完销毁,需要保存到本地的信息使用AES加密后保存,AES密钥及加密方法封装为静态库保存,尽量提高反编译的难度.

四.反编译防护
现在的反编译技术已经十分强大了,能查到的方法不是失效了就是不能通过苹果的机审.由于现在的破解技术已经能获取系统的root权限并且可以手动开辟线程运行自己的代码,想做到绝对的安全对于小公司或者技术力量不强大的公司基本没可能了,在几天的研究中总结了几个方法:

1.防tweak依附 ,防gdb调试
tweak和gdb我就不解释了,想了解的可以去google,我只说得到的解决方法,不过记住这样做只能提高反编译的难度,保护总比破坏难,能做总比不做好,下面代码都是在main.m中.

#include<dlfcn.h>
#import <UIKit/UIKit.h>
#import "AppDelegate.h"

// 防tweak依附
static __inline__ __attribute__((always_inline)) int anti_tweak()
{
    uint8_t lmb[] = {'S', 'u', 'b', 's', 't', 'r', 'a', 't', 'e', '/', 'D', 'y', 'n', 'a', 'm', 'i', 'c', 0, };
    NSString *dir = [NSString stringWithFormat:@"/%@/%@%s%@", @"Library", @"Mobile", lmb, @"Libraries"];
    NSArray *dirFiles = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:dir error:nil];
    NSArray *plistFiles = [dirFiles filteredArrayUsingPredicate:
                           [NSPredicate predicateWithFormat:
                            [NSString stringWithFormat:@"%@ %@%@ '.%@%@'",@"self", @"EN", @"DSWITH", @"pli", @"st"]]];
    int cnt = 0;
    for (NSString *file in plistFiles) {
        NSString *filePath = [dir stringByAppendingPathComponent:file];
        NSString *fileContent = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil];
        if (fileContent && [fileContent rangeOfString:[[NSBundle mainBundle] bundleIdentifier]].location != NSNotFound) {
            cnt ++;
        }
    }
    // 返回有针对本 app 的 tweak 数量,为 0 说明没有
    return cnt;
}

// 防止GDB挂起
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, char * argv[]) {
#if DevelopMent == 0    // 只在生产环境检测 因为它会关闭调试模式 控制台无法输出
    disable_gdb();
#endif
    // 防tweak依附
    if (anti_tweak() != 0  || getenv("DYLD_INSERT_LIBRARIES") != NULL) {
        exit(0);
    }
    @autoreleasepool {
        return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
    }
}

2.安装包文件完整性检测
原理就是将每次打包后的文件列表的MD5值保存在服务器端,每次APP启动时校验本地文件,如果不一致做出相应处理.代码:

#import "FileHash.h" // GitHub上搜索
/**
 比对文件哈希值 校验完整性
 @param info 服务器端的文件哈希值
 */
+ (void)toGetVersionWithInfo:(NSDictionary *)info {
    if (![info isEqualToDictionary:[self getBundleFileHash]]) {
        exit(0);
    }
}

//获得所有资源文件名
- (NSArray *)allFilesAtPath:(NSString *)dir{
    NSMutableArray * arr = [NSMutableArray array];
    NSFileManager * manager = [NSFileManager defaultManager];
    NSArray *temp = [manager contentsOfDirectoryAtPath:dir error:nil];
    
    for (NSString * fileName in temp) {
        BOOL flag = YES;
        NSString * fullpath = [dir stringByAppendingPathComponent:fileName];
        if ([manager fileExistsAtPath:fullpath isDirectory:&flag]) {
            if (!flag ) {
                [arr addObject:fileName];
                //                NSLog(@"%@",fileName);
            }
        }
    }
    return arr;
}

//生成资源文件名及对应的hash的字典, eg:@{@"appicon":@"wegdfser45t643232324234"};
- (NSDictionary *)getBundleFileHash{
    NSMutableDictionary * dicHash = [NSMutableDictionary dictionary];
    NSArray * fileArr = [self allFilesAtPath:[[NSBundle mainBundle]resourcePath]];
    for (NSString * fileName in fileArr) {
        //对应的文件生成hash
        NSString * HashString = [FileHash md5HashOfFileAtPath:[[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:fileName]];
        if (HashString != nil) {
            [dicHash setObject:HashString forKey:fileName];
        }
    }
    //所有资源文件的hash就保存在这数组里
//    NSLog(@"-----%@",dicHash);
    return dicHash;
}

3.方法名混淆
方法名混淆现在不好过机审,建议只用于关键方法,怎么做大家自己搜索吧,关键词: confuse.sh func.list

4.App切换到后台之后截图防护
做法就是在切换时候添加蒙版

- (void)applicationWillResignActive:(UIApplication *)application {
    _bar = [[UIToolbar alloc]initWithFrame:[UIScreen mainScreen].bounds];
    _bar.barStyle = UIBarStyleBlackTranslucent;
    [self.window addSubview:_bar];
}
- (void)applicationDidBecomeActive:(UIApplication *)application {
    [_bar removeFromSuperview];
    _bar = nil;
}

目前项目中做的防护就这些了,希望大家一起交流.

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,717评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,501评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,311评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,417评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,500评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,538评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,557评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,310评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,759评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,065评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,233评论 1 343
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,909评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,548评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,172评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,420评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,103评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,098评论 2 352

推荐阅读更多精彩内容

  • Android实现高性能的帧动画礼物播放效果 引言:我们都知道Android实现动画的常见方式有那么几种,比如属性...
    遥望星空forward阅读 843评论 0 0
  • 一、晚上9-11点为免疫系统(淋巴)排毒时间,此段时间应安静或听音乐。 二、晚间11-凌晨1点,肝的排毒,需在熟睡...
    AmyZhang_31b9阅读 210评论 0 0
  • 又到很晚的时间,我总是会在夜深人静的时候想很多,关于我,关于我们的记忆。当独处的时候,我总是会一遍遍想念着...
    忆娟阅读 166评论 0 0
  • 独自一人在宿舍里蜗居了好多天,看到有的人来了,有的人走了。感触颇深。人们都说人走茶凉,以前也觉得若没有永恒何必曾经...
    旅行在路上1993阅读 284评论 5 3
  • 在一个晴朗周末的上午,我和爱人外出散步,打算围着汉城湖转上一圈。在接近汉武帝巨大雕像的湖畔酒店边上,我们看到那里正...
    朴索君阅读 169评论 0 0