iOS App的几种安全防范

虽然公司的项目目前还不算健壮,安全问题对于大部分小公司来说似乎并没什么必要,不过要攻击的话,我有十足的把握,我们是无法承受冲击的。嘿嘿嘿~不过带着一颗入坑iOS的心思,搜集了一下资料后,还是做了一些尝试。

iOS App安全防范总结:

1.防止抓包篡改数据
2.防止反编译
3.阻止动态调试
4.防止二次打包

关键检测:越狱检测

  • OK,下面是正文开始。

1.防止抓包篡改数据

对于抓包,利用神器charles的操作会在另外的文章单独介绍。如果不懂以下为利用charles抓包。
charles抓包教程

若别人真想抓你程序包,该如何防范呢?我目前只能说,let it go ~ let it go~随他抓,随他抓。因为基本上只要想抓取程序访问的数据,基本上是能抓取到的。对于iOS来说,目前我是做了两种操作。

1)判断是否设置了代理
对于抓包,现在的手段基本是设置代理,所以我们可以通过判断是否设置了代理的方式来进行下一步的防范。

#在网络请求前插入这个方法,再根据需求做相应的防范
+ (BOOL)getDelegateStatus
{
    NSDictionary *proxySettings = CFBridgingRelease((__bridge CFTypeRef _Nullable)((__bridge NSDictionary *)CFNetworkCopySystemProxySettings()));
    NSArray *proxies = CFBridgingRelease((__bridge CFTypeRef _Nullable)((__bridge NSArray *)CFNetworkCopyProxiesForURL((__bridge CFURLRef)[NSURL URLWithString:@"http://www.google.com"], (__bridge CFDictionaryRef)proxySettings)));
    NSDictionary *settings = [proxies objectAtIndex:0];
    NSLog(@"host=%@", [settings objectForKey:(NSString *)kCFProxyHostNameKey]);
    NSLog(@"port=%@", [settings objectForKey:(NSString *)kCFProxyPortNumberKey]);
    NSLog(@"type=%@", [settings objectForKey:(NSString *)kCFProxyTypeKey]);
    if ([[settings objectForKey:(NSString *)kCFProxyTypeKey] isEqualToString:@"kCFProxyTypeNone"])
    {
        //没有设置代理
        return NO;

    } else {
        //设置代理了
        return YES;
    }
}

2)RSA
通过与后台的配合,设置公钥与私钥,对请求数据和返回数据进行加密。这里另外起一篇单独介绍。

2.防止反编译(防止class-dump、hopper反编)

越狱检测

一般能拿到自己ipa包都需要有一台越狱的手机

  • 判断设备是否安装了越狱常用工具:
    一般安装了越狱工具的设备都会存在以下文件:
    /Applications/Cydia.app
    /Library/MobileSubstrate/MobileSubstrate.dylib
    /bin/bash
    /usr/sbin/sshd
    /etc/apt
  • 判断设备上是否存在cydia应用
  • 是否有权限读取系统应用列表
    没有越狱的设备是没有读取所有应用名称的权限
  • 检测当前程序运行的环境变量 DYLD_INSERT_LIBRARIES
    非越狱手机DYLD_INSERT_LIBRARIES获取到的环境变量为NULL。

综上所述,检查设备是否越狱

+ (BOOL)isJailbroken {
    // 检查是否存在越狱常用文件
    NSArray *jailFilePaths = @[@"/Applications/Cydia.app",
                               @"/Library/MobileSubstrate/MobileSubstrate.dylib",
                               @"/bin/bash",
                               @"/usr/sbin/sshd",
                               @"/etc/apt"];
    for (NSString *filePath in jailFilePaths) {
        if ([[NSFileManager defaultManager] fileExistsAtPath:filePath]) {
            return YES;
        }
    }

    // 检查是否安装了越狱工具Cydia
    if([[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:@"cydia://package/com.example.package"]]){
        return YES;
    }

    // 检查是否有权限读取系统应用列表
    if ([[NSFileManager defaultManager] fileExistsAtPath:@"/User/Applications/"]){
        NSArray *applist = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:@"/User/Applications/"
                                                                               error:nil];
        NSLog(@"applist = %@",applist);
        return YES;
    }

    //  检测当前程序运行的环境变量
    char *env = getenv("DYLD_INSERT_LIBRARIES");
    if (env != NULL) {
        return YES;
    }

    return NO;
}

代码混淆

这里生成混淆代码的方法我们通过shell脚本来实现,同时我们需要一个文档来写入我们需要进行混淆的方法名或是变量名。

  • 打开终端,cd到文件所在目录,使用

touch confuse.sh
touch func.list

此时将目录中的.sh和.list文件拖入项目中

  • 写入shell脚本

在项目中找到刚刚拖进来的.sh文件,在confuse.sh中写入脚本

#!/bin/bash

# 这是Shell脚本,如果不懂shell,自行修炼:http://www.runoob.com/linux/linux-shell.html

# 以下使用sqlite3进行增加数据,如果不了解sqlite3命令,自行修炼:http://www.runoob.com/sqlite/sqlite-tutorial.html

#数据表名
TABLENAME="CodeObfuscationOC"

#数据库名
SYMBOL_DB_FILE="CodeObfuscation.db"

#要被替换的方法列表文件
STRING_SYMBOL_FILE="$PROJECT_DIR/ConfusionDemo/func.list"

#被替换后的宏定义在此文件里
HEAD_FILE="$PROJECT_DIR/$PROJECT_NAME/CodeObfuscation.h"

#维护数据库方便日后做bug排查
createTable()
{
echo "create table $TABLENAME(src text,des text);" | sqlite3 $SYMBOL_DB_FILE
}

insertValue()
{
echo "insert into $TABLENAME values(‘$1‘,‘$2‘);" | sqlite3 $SYMBOL_DB_FILE
}

query()
{
echo "select * from $TABLENAME where src=‘$1‘;" | sqlite3 $SYMBOL_DB_FILE
}

#生成随机16位名称
randomString()
{
openssl rand -base64 64 | tr -cd ‘a-zA-Z‘ | head -c 16
}

#删除旧数据库文件
rm -f $SYMBOL_DB_FILE

#删除就宏定义文件
rm -f $HEAD_FILE

#创建数据表
createTable

#touch命令创建空文件,根据指定的路径
touch $HEAD_FILE
echo ‘#ifndef CodeObfuscation_h
#define CodeObfuscation_h‘ >> $HEAD_FILE
echo "//confuse string at `date`" >> $HEAD_FILE

#使用cat将方法列表文件里的内容全部读取出来,形成数组,然后逐行读取,并进行替换
cat "$STRING_SYMBOL_FILE" | while read -ra line;
do
if [[ ! -z "$line" ]]
then
random=`randomString`
echo $line $random

#将生成的随机字符串插入到表格中
insertValue $line $random

#将生成的字符串写入到宏定义文件中,变量是$HEAD_FILE
echo "#define $line $random" >> $HEAD_FILE
fi
done
echo "#endif" >> $HEAD_FILE
sqlite3 $SYMBOL_DB_FILE .dump
  • 添加run script命令

640.jpg

  • 然后添加$PROJECT_DIR/ConfusionDemo/confuse.sh

  • 给脚本授权

接下来还是在我们项目的文件夹下,通过终端给我们的脚本赋予最高权限

chmod 777 confuse.sh
  • 添加预编译文件PCH

6401.jpg

然后配置PCH文件

6402.jpg

  • 添加$PROJECT_DIR/ConfusionDemo/PrefixHeader.pch

  • 生成CodeObfuscation.h文件

这时候我们编译一下代码,会发现项目中多出了一个CodeObfuscation.h文件(如果没有,可到项目文件夹中找,我的就是在文件夹里找到的- -,然后拖进项目)。这个文件就是替换方法名的文件,我们在PCH文件中引入他。

  • 在func.list中添加准备替换的方法名

在项目中点开之前拖进来的func.list文件,然后在里面加入自己想要混淆的方法名

//此处方法名为项目中自己编码的方法名,不可混淆系统方法名
viewControllerTestMethodA
viewControllerTestMethodB
viewControllerTestMethodC
viewControllerMethodWithParameter
testString
testArray
testMutDic
  • 结果

编译之后

#ifndef CodeObfuscation_h
#define CodeObfuscation_h

#define viewControllerTestMethodA CTBxmOXAbJYekhnH
#define viewControllerTestMethodB RnPEjnXygFXLdikO
#define viewControllerTestMethodC IzHlDYOpaAFYFTXa
#define viewControllerMethodWithParameter nWqyalBcfoUSRVpc
#define testString MNPoVYdmCcklAnCO
#define testArray kHMRxPlGXGeqekxL
#define testMutDic hphPSODIvbBFSTHX
#endif

看到 CodeObfuscation有这种变化,恭喜你,已经代码混淆成功。即使通过class-dump反编出来的,也只是一堆乱码。

  • 需要注意的几点

    不可以混淆iOS中的系统方法;

    不可以混淆iOS中init等初始化方法;

    不可以混淆xib的文件,会导致找不到对应文件;

    不可以混淆storyboard中用到的类名;

    混淆有风险,有可能会被App Store以2.1大礼包拒掉。

3.阻止动态调试

GDB、LLDB是Xcode内置的动态调试工具。使用GDB、LLDB可以动态的调试你的应用程序(通过下断点、打印等方式,查看参数、返回值、函数调用流程等)。

为了阻止hackers使用调试器 GDB、LLDB来攻击你的App,你可以在main.m文件中插入以下代码:

#import <dlfcn.h>
#import <sys/types.h>

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[]) {
    // Don‘t interfere with Xcode debugging sessions.
    #if !(DEBUG)
        disable_gdb();
    #endif

    @autoreleasepool {
        return UIApplicationMain(argc, argv, nil,
            NSStringFromClass([MyAppDelegate class]));
    }
}

4.防止二次打包

iOS 和 OS X 的应用和框架包含了二进制代码和所需要的资源文件(如:图片、不同的语言文件、XIB/Storyboard文件、profile文件等),在通过开发者私钥签名程序包时,对于可执行文件( Mach-O ),会将签名直接写入到该文件中,而对于其他的资源文件,会统一写到 _CodeSignature 文件下的 CodeResources 文件中,它仅仅是一个 plist 格式文件。

这个列表文件中不光包含了文件和它们的签名的列表,还包含了一系列规则,这些规则决定了哪些资源文件应当被设置签名。伴随 OS X 10.10 DP 5 和 10.9.5 版本的发布,苹果改变了代码签名的格式,也改变了有关资源的规则。如果你使用10.9.5或者更高版本的 codesign 工具,在 CodeResources 文件中会有4个不同区域,其中的 rules 和 files 是为老版本准备的,而 files2 和 rules2 是为新的第二版的代码签名准备的。最主要的区别是在新版本中你无法再将某些资源文件排除在代码签名之外,在过去你是可以的,只要在被设置签名的程序包中添加一个名为 ResourceRules.plist 的文件,这个文件会规定哪些资源文件在检查代码签名是否完好时应该被忽略。但是在新版本的代码签名中,这种做法不再有效。所有的代码文件和资源文件都必须 设置签名,不再可以有例外。在新版本的代码签名规定中,一个程序包中的可执行程序包,例如扩展 (extension),是一个独立的需要设置签名的个体,在检查签名是否完整时应当被单独对待。

有些hacker可能会通过篡改你的程序包(包括资源文件和二进制代码)加入一些广告或则修改你程序的逻辑,然后重新签名打包,由于第三方hacker获取不到签名证书的私钥,因此会替换掉程序包中签名相关的文件embedded.mobileprovision,我们可以直接检查此文件是否被修改,来判断是否被二次打包,如果程序被篡改,则退出程序。
检测embedded.mobileprovision是否被篡改:

// 校验值,可通过上一次打包获取
#define PROVISION_HASH @"w2vnN9zRdwo0Z0Q4amDuwM2DKhc="
static NSDictionary * rootDic=nil;

void checkSignatureMsg()
{
    NSString *newPath=[[NSBundle mainBundle]resourcePath];

    if (!rootDic) {

        rootDic = [[NSDictionary alloc] initWithContentsOfFile:[newPath stringByAppendingString:@"/_CodeSignature/CodeResources"]];
    }

    NSDictionary*fileDic = [rootDic objectForKey:@"files2"];

    NSDictionary *infoDic = [fileDic objectForKey:@"embedded.mobileprovision"];
    NSData *tempData = [infoDic objectForKey:@"hash"];
    NSString *hashStr = [tempData base64EncodedStringWithOptions:0];
    if (![PROVISION_HASH isEqualToString:hashStr]) {
        abort();//退出应用
    }
}

参考

https://blog.csdn.net/u011656331/article/details/81120420
https://mp.weixin.qq.com/s/zD5EtFpSzKQ0h-ORTC9WqQ

作者:小苏羿
链接:https://www.jianshu.com/p/0cfb5859f15f
来源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

原文地址:https://www.cnblogs.com/tangyuanby2/p/11384481.html

时间: 2024-10-13 23:20:26

iOS App的几种安全防范的相关文章

怎样判断iOS App是通过哪种途径启动的?

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions说明:当应用程序启动时执行,应用程序启动入口.只在应用程序启动时执行一次.application参数用来获取应用程序的状态.变量等,值得注意的是字典参数:(NSDictionary *)launchOptions,该参数存储程序启动的原因.1.若用户直接启动,lauchOptions

ios app在itunesConnect里面的几种状态

原地址:http://blog.csdn.net/dean19900504/article/details/8164734 Waiting for Upload (Yellow) Appears when you’ve completed entering your metadata, however, you have not finished uploading your binary or have chosen to upload your binary at a later time.

iOS App之间常用的五种通信方式及适用场景总结

iOS系统是相对封闭的系统,App各自在各自的沙盒(sandbox)中运行,每个App都只能读取iPhone上iOS系统为该应用程序程序创建的文件夹AppData下的内容,不能随意跨越自己的沙盒去访问别的App沙盒中的内容. 所以iOS 的系统中进行App间通信的方式也比较固定,常见的app间通信方式以及使用场景总结如下. 1.URL Scheme 这个是iOS app通信最常用到的通信方式,App1通过openURL的方法跳转到App2,并且在URL中带上想要的参数,有点类似http的get请

用Xamarin和Visual Studio编写iOS App

一说开发 iOS app,你立马就会想到苹果的开发语言 Objective C/Swift 和 Xcode.但是,这并不是唯一的选择,我们完全可以使用别的语言和框架. 一种主流的替换方案是 Xamarin,这是一个跨平台框架,允许你开发 iOS.Android 和 OSX.Windows app,它使用的是 C# 和 Visual Studio.最大的好处在于,Xamarin 允许你在 iOS 和 Android app 间共享代码. Xamarin 与其他跨平台框架相比有一个最大的好处:使用

hbuilder IOS APP 打包与发布

---恢复内容开始--- 准备:苹果开发者账号,一个Mac系统 没有账号可以再这里注册 https://developer.apple.com/ 因为账号是公司的,自己并没有注册过,这里就不进行阐述了. iOS有两种证书和描述文件: 1 开发(Development)证书和描述文件   (用于开发测试,在HBuilder中打包后可在真机环境通过Safari调试) 2 发布(Distribution)证书和描述文件  (用于提交Appstore,在HBuilder中打包后可使用Applicatio

iOS App的状态

Refer: App States and Multitasking iOS设备的系统资源有限,所以App在前台运行和在后台运行的时候是有区别的.为了节省电池寿命和用户体验,App在后台运行的时候,有一些功能会被操作系统限制. 当App在前台运行的时候,可以处理系统发送的touch事件.UIKit基础架构已经做了大部分的工作用来把事件分发到自定义的对象上,开发者只需要重写一些相应的方法. 在App的开发过程中建议遵守的方针: (Required)对状态的切换做出适当的相应,否则可能会造成数据丢失

ios app开发步骤

虽然开发一个app的任务看上去可能很艰巨,但是整个过程可以抽象成几个相对简单的步骤,下面这些步骤会在你开发第一个app时帮你步入正途. 定义Concept 每个好app都是从一个concept开始. 获得这个concept的最好方法就是考虑你打算用你的app解决什么问题,好的app解决的问题都是单一,定义清晰的问题,比如,Settings app允许用户调整设备的所有设置,它给用户提供了一个独立界面让用户来完成一系列相关的任务. 下面是获得一个好concept的一些关键问题: 受众是谁?你app

学习 About iOS App Programming 第三天

-------State Preservation and Restoration 即使我们的app能支持后台运行,但它也不能一直在后台运行,有一些情况,系统也许会需要终止app,为了释放内存给在前台运行的app.但是用户不关心app是不是被关闭,用户只知道这个app应用就是这个地方暂停了,当再次起来时应该就在上一次退出的地方.这样用户能继续进行他上次没有完成的任务.因此UIKit实现了这种功能. UIKit的状态保存系统提供了一个简单同时比较精准的基础技术对于保存和恢复app viewcont

20个可以帮你简化iOS app开发流程的工具

这里推荐20个可以帮你简化iOS app开发流程的工具.很多开发者都使用过这些工具,涉及原型和设计.编程.测试以及最后的营销,基本上涵盖了整个开发过程. 原型和设计 有了一个很好的创意后,你要做的不是立刻编程,而是设计UI和创建原型,这样你才能知道app如何运行,根据用户体验需要做哪些调整. App Cooker AppCooker 不仅是一个创建原型的优秀工具,它提供的许多功能还可以帮助你将程序发布到App store中.它集成了Dropbox,Box.net和photo roll,你可以直接