iOS 自己动手篡改 APP 网络请求及简单防护

前言

在开始谈技术干货之前,先大概说一下这次公司APP安全风波的始末,甩锅的理由有三,其一:创业公司凡事讲究敏捷开发,快速迭代上线,因此在完成功能需求之余无暇他顾;其二:安全问题应该为技术总监着重考虑的一点,但是(按照惯例,这里省略N字,不可描述);其三:后台接口定义也没有考虑到这一点,然而,从不要随便甩锅的好习惯来说,我还是要负起责任的,毕竟自己是iOS负责人,要对APP有个全面的把握.

简单的讲下事情经过,就是突然有一天下午,一个用户打电话给客服说自己买了一张998元的机票买错了,想退票,要求公司给他取消订单退钱,然后还把支付宝的网页支付记录发了过来(后来证实是PS过的).然后财务部那边查账之后发现这个用户的支付宝账号确实付款了,但实际付款的只有1元,然后公司财务就把事情反馈给了副总,然后整个技术部就炸锅了,都在各抒己见分析这个1元钱是怎么通过APP付款到公司账户的,因为机票订单是没有1元的.而且APP和支付宝给后台的回调都是支付成功的.根据唯物主义思想来推断,支付宝出错的概率远小于我们APP出错的概率,而且后台也没有被攻入的迹象,因此就把问题锁定在APP上了,然后我们用的POST请求(一些人说比较安全,其实不加密的话,安全性和GET请求比起来相差无几),我们部门的首席科学家直接说APP肯定是被反编译了,原话是”我找我阿里的朋友帮忙,分分钟就把APP反编译了,然后随便下单.”当时听了这话我是懵逼的,虽然从技术可操作性来说,存在反编译的可能,但是分分钟不费吹灰之力就反编译这种说法我是不太能接受的,然后就有了后边我自己攻击自己APP的举动.

正题

我的分析就是反编译太麻烦,不容易实施,而且即使反编译出来了,一个类名一个方法名的去解析APP也很累,所以就从相对好实施的篡改网络请求及返回数据下手!之前看过唐巧大神的一篇关于Charles的使用讲解,不过当时是用来简单的抓别人的包,用点数据就放下了,现在就拿来实践一下篡改数据这个功能,首先安装好Charles,然后按部就班的把Charles设置为自己mac电脑的代理,

111392599-a688db3407fce594

然后手机连自己电脑wifi,或者跟电脑连接同一个wifi都可以,然后设置手机的代理,让你手机的网络请求都经过Charles,服务器里填写的是电脑的IP地址,

121392599-b8c6765b079285ca

端口默认的就是8888:

131392599-7c80cfb2c3ecfaaf

这样就可以抓到APP跟服务器之间的网络请求了.然后在查看请求之后去使用篡改功能,这里就演示一下篡改一个页面的数据

141392599-4f2eea2f4d13660c

这里的第一个票价是12500,下边是拦截到的请求

151392599-8dacca0618ca7e20

给这个IP地址对应的8080端口的请求都加上断点,点击那个Breakpoints,然后当下一次请求进来的时候,就可以直接篡改数据

161392599-85b4e6633b869a8d

篡改数据的步骤可以看下方的gif图:

之后点击”Execute”,返回给APP数据,这样APP展示的页面就变成了:

171392599-256d3877c2aa17a1

到这里用户的骗术就被还原了,当然后边还需要篡改一些数据才能成功去下单支付这个1元订单,细节就不在赘述了

181392599-29b041f86f86fc2a

那个支付宝支付显示不全是因为iOS10字变宽了,当然支付成功之后的心情是很复杂的,毕竟自己的APP被这么轻易搞出问题了,大家可以设身处地想一下哈,后边重点来了,讲解一下小公司的解决方案.
因为开发压力比较大,所以要考虑性价比比较高的方案,这里就暂时舍弃了HTTPS,运用了实施起来相对简单的MD5加密,这里有两种情况,下载加密和上传加密,比如说刚才看到的订单列表就属于下载加密,要确保订单列表数据一旦被篡改就不去使用,而点击立即支付的下单动作就是上传加密,要确保传给服务器的下单参数一旦被篡改就不去使用,MD5加密的原理就不在这里讲了,因为我之前的文章JSPatch里已经讲过了,主要说一下具体的实施细节以及过程中遇到的小坑,首先是下载加密:

191392599-408ce2ee0d0506e1
我用的网络请求是自己封装的AFN,然后这里设置一下直接字符串取值,不要转成JSON:manager.responseSerializer = [AFHTTPResponseSerializer serializer];
取出HTTP Header里的验证字串:
NSDictionary *headerDic = [operation.response allHeaderFields];
NSString *rsaValue = headerDic[@"rsaValue"];
然后取值:NSString *responseObjectStr = [[NSString alloc] initWithData:responseObject encoding:NSUTF8StringEncoding];
加密:NSString *md5Str = [NSString stringWithFormat:@"%@%@", responseObjectStr, md5SaltValue];
然后进行比对校验[[md5Str getMd5_32Bit] isEqualToString:headerDic[@"rsaValue"]]
然后是上传加密:
201392599-a0380e7b76a53fac
把所有参数转换为String:String *jsonString = [self.orderModel yy_modelToJSONString];
加密:NSString *md5Value = [[NSString stringWithFormat:@"%@%@",jsonString,md5SaltValue] getMd5_32Bit];
设置请求头:[manager.requestSerializer setValue:md5Value forHTTPHeaderField:@"rsaValue"];
到这里,这篇文章算是告一段落,后边应该会更新一系列安全相关的文章,不过需要一个我去学习然后理解然后实践的过程~下一篇是动手去反编译自己APP开始踩坑之旅.当然都是我自己的浅显青铜操作,欢迎同学们指点及大神们一笑而过.
2 6 收藏 2 评论

相关文章

可能感兴趣的话题



直接登录
最新评论
跳到底部
返回顶部