App签名二三事

一、概述

相比于Android系统,iOS对下载到设备中的软件有比较严格的限制;绝大多数人,只会从AppStore下载App,这也杜绝了很多安全隐患;但是对于iOS开发者来说,需要搞明白很多事情(如:iOS App的签名原理),甚至需要做一些小动作(如重签名)来达到自己(友好的)目的。

1、基础概念

  • 摘要算法:把一个任意长度的字节串映射 为一定长度的十六进制的数字串;这个数字串称为哈希值。常见有:MD5、SHA1、SHA256、SHA512等

  • 对称加密:加密和解密使用相同密钥,常见有:DES算法、3DES算法和AES算法等;

  • 非对称加密:加密和解密使用不同密钥的加密算法,用公钥加密的数据,要用私钥才能解密,用私钥加密的数据,要用公钥才能解密;常用加密算法有:RSA、Elgamal、背包算法等;

  • 数字签名(digital signature):

    • 是非对称加密与摘要算法的结合,用于验证数据的完整性及不可抵赖性;
    • 发送方对数据计算出摘要信息,然后用发送方私钥加密,得到摘要密文,这就是数字签名;
    • 接收方收到后,利用发送方的公钥和非对称算法从数字签名中获取摘要明文;根据原始内容计算出摘要 和 解密出来的摘要明文进行对比;不一致,说明内容被篡改 or 收到内容不是指定发送方;
  • 数字证书(digital certificate):

    • 数字证书数为了保护发送方公钥不被伪造而发明的,引入证书中心(Certificate Authority,CA)概念,CA用自己的私钥,对发送方的公钥和一些相关信息一起加密,生成”数字证书”(Digital Certificate)。
    • CA的数字证书中有:签发者、证书用途、发送方公钥、发送方非对称加密算法、发送方HASH算法和到期时间等
    • 接收方拿到数字证书后,先从数字证书中解密出发送方公钥(用的是CA的公钥和CA解密算法);然后根据发送方公钥去解密数字证书,得到摘要;最后比对原始数据计算出的摘要是否一致。
    • CA是第三方机构,CA公钥是公开的,接收方可以跟别人比对(比如网上查),因此不可能伪造。而发送方公钥,是接收方从数字证书中获得的。
    • 数字证书在https协议实现中有重要应用

2、签名相关的几个概念

名称作用
证书(cer)内容是公钥或私钥,由其他机构对其签名组成的数据包。
Entitlements包含了 App 权限开关列表
CertificateSigningRequest本地公钥
p12本地私钥,可以导入到其他电脑。
Provisioning Profile包含了 证书 / Entitlements 等数据,并由苹果后台私钥签名的数据包。

3、iOS包渠道及其签名机制

  • iOS设备上App的渠道粗分有AppStore渠道非AppStore渠道,非AppStore包有:Testflight内测包、In-House 企业内部分发包、Ad-Hoc(相当于企业分发的限制版,限制安装设备梳理)和Xcode调试安装;(越狱包不在此范围)。

  • AppleStore中渠道包签名验证

    • 苹果官方生成一对公私钥,在 iOS 系统中内置一个公钥,私钥由苹果后台保存。
    • App 上传到 App Store 时,苹果后台用私钥对 App 数据进行签名(计算出摘要,再私钥加密);
    • iOS 下载这个 App 后,用公钥验证这个签名,如果签名正确则这个 App 肯定是由苹果后台认证的,并且没有被修改或损坏。
  • 非AppleStore渠道包的签名验证需要使用双重签名机制,保证不被滥用。

二、双重签名机制

1、简介

  • 使用两对公私钥做加密验证,分别是 Mac本地的一对公私钥Apple提供的一对公私钥(私钥在苹果后台,公钥在每个 iOS 设备上)。
  • 双重签名的存在是为了满足:
    • App 需要经过苹果允许才能安装;
    • 在 Apple 后台中注册过的设备才能安装,比如在 TestFlight 内测、真机调试模式下;
    • 限制签名只能对应唯一的 App;

2、重要概念

  • Mac 上执行钥匙串访问 -> 证书助理 -> 从证书颁发机构请求证书…,就会在Mac本地生成了一对公私钥,导出的 CSR 文件(CertificateSigningRequest.certSigningRequest)就是 Mac 公;

  • CSR 文件上传到苹果后台,苹果用Apple私钥对其签名,并生成一份包含Mac公钥信息 和 苹果签名信息的开发/发布证书cer

  • 当我们将cer下载并安装到Mac后,keychain会把CertificateSigningRequest和cer证书关联起来。在钥匙串中找到该证书,可以导出Mac私钥(.p12 文件)

  • 在苹果后台需要配置AppID、可用设备IDs(企业证书不需要) 和 Entitlements(App 权限开关列表),对这些额外信息 和 cer证书使用Apple私钥签名,最后苹果将证书 + 额外信息 + 签名组成一个Provisioning Profile文件(后缀mobileprovision),可下载到Mac上。

    Provisioning Profile文件又被成为描述文件,安装好后,存放在~/Library/MobileDevice/Provisioning Profiles路径下
    

3、App签名和验证

双签名和验证

  • 在Mac上编译完一个App后,Mac先用Mac私钥对App签名,并将Provisioning Profile文件也打包到App中,文件名为embedded.mobileprovision

  • iOS系统安装App时,苹果通过内置在手机中的Apple公钥验证embedded.mobileprovision中的签名是否正确,接着验证证书中的签名是否正确

  • 在确保embedded.mobileprovision里的数据都是苹果授权以后,就从里面取出数据,做后续各种验证,包括

    • 用Mac公钥验证App签名
    • 验证设备 ID 是否在 ID 列表上
    • 验证证书是否过期
    • 验证AppID 是否对应得上
    • 验证权限开关是否跟 APP 里的 Entitlements 对应等等。
  • 如果别的 Mac 也要编译后签名这个 App,就必须要获取申请生成cer证书那个Mac机器上的私钥;这个比较简单,只需要在那台机器的钥匙串中找到cer证书,然后右键导出Mac私钥(.p12 文件);

  • 简单来说,要在别人设备上成功编译成功并将App安装到设备中,需要cer证书导出的**.p12文件和Provisioning Profile文件**(描述文件)

4、补充

  • 双层代码签名是针对开发测试包、In-House 企业签名、Ad-Hoc 包为例的签名和验证的流程,只是企业签名不限制安装的设备数,因此描述文件中不会有设备列表,而是一条 ProvisionsAllDevices 记录。
  • 从 App Store 上下载的安装包,里面是没有描述文件的,但上架之前还是要配置证书、PP 文件,因为 App ID 和权限的检验还是需要做的。但 App 上传到 AppStore 以后就跟 PP 文件没有关系了,所以我们可以理解为 App Store 上包的签名验证采用就是前面说的最简单的签名方式,Apple 后台直接用私钥签名 App 就可以了。

三、App重签名

1、概述

  • 重签名本质是将已发布/未发布的包重新签名为自己的证书和签名,关键点是替换ipa内的证书描述文件
  • 使用codesign工具

2、重签名方案

  • 查看ipa包是否加壳,只有未加壳的包才可以重签名。

    otool -l app_name.app/app_name | grep crypt
    
    # 输出cryptid为0代表已经砸壳,即解密,为1或者2表示以第1类或者第2类加密方案加密。
    
  • 查看本地证书列表并记录下要用来签名的证书名,例如”iPhone Distribution: XXXXX (XXX)”

    security find-identity -v -p codesigning
    # 输出有效的证书列表
    
  • 创建一个和App同名的工程,从上步得到有效证书列表中,选择一个,编译后生成新App;将这个新App里embedded.mobileprovision文件取出替换iap包中的文件。

  • 删除ipa包内部不能被重签名的插件(PlugIns文件夹 和 Watch文件夹)

  • 将ipa包内的所有Framework中Mach-O文件重签名(Frameworks目录下有Framework)

# 命令参考
codesign -fs [证书名称] [要签名的文件]

#如果没有权限,执行chmod +x app_name.app/app_name 给Mach-O文件添加可执行权限
#Frameworks文件夹里面的.framework本质还是文件夹,真正要重签的是.framework里面的MachO可执行文件
  • 将ipa包内info.plist的BundleId修修改为新App对应的的BundleId

  • 用命令查看embedded.mobileprovision文件,找到其中的entitlements字段,并且复制entitlements字段和其中的内容。

    security cms -D -i 「embedded文件路径」
    
  • 新建entitlements.plist文件,将复制内容拷贝到文件中,然后将entitlements.plist复制到ipa的同级目录下。

  • 对App进行重签名,并压缩成新的ipa包

    # 重签名
    $ codesign -fs "iPhone Distribution: XXXXX (XXX)" --no-strict --entitlements=entitlements.plist
    // --no-strict 不严谨的 
    // --entitlements=entitlements.plist权限所在文件是entitlements.plist
    codesign -fs 签名证书 --no-strict --entitlements=entitlements.plist app_name.app
    
    # 压缩ipa包
    $ zip -r 「输出的文件名(.ipa)」 Payload/
    
  • 将ipa包安装到手机,若能同时存在两个应用且能正常运行则表示重签名成功。

3、防止App被重签名办法

  • 校验描述文件信息:在启动时校验描述文件信息与打包时是否一致。例如判断组织单位:
    先记录证书中的组织单位信息。
  • sysctl检测是否被调试,具体可见iOS安全防护之重签名防护和sysctl反调

4、目的

  • 对于大多数iOS开发,了解App签名原理,知道要对App做防止重签名的保护即可。
  • 本人并非从事越狱安全工作;使用重签名,主要是为了让测试包可以支持IAP测试,搞过IAP的同学应该明白IAP测试中的痛点: 使用TestFlight or ad-hoc包测试的效率真的会把人逼疯,企业内测又不支持[坑]

历史文章

浅谈数据加密

浅谈代码混淆

参考文章

代码签名探析

iOS App 签名的原理

iOS应用安全3 — APP重签名

https://juejin.im/post/5e89d0fd5188257399158b52

「点点赞赏,手留余香」

    还没有人赞赏,快来当第一个赞赏的人吧!
0 条回复 A 作者 M 管理员
    所有的伟大,都源于一个勇敢的开始!
欢迎您,新朋友,感谢参与互动!欢迎您 {{author}},您在本站有{{commentsCount}}条评论