名称解释
代码签名是对可执行文件或脚本进行数字签名.用来确认软件的来源并保证在签名后未被修改或损坏的措施。和数字签名原理一样,只不过签名的数据是代码而已.
为什么要使用代码签名?
在iOS出来之前,以前的主流操作系统软件随便从哪里下载都能运行,系统安全存在隐患,盗版软件,病毒入侵,静默安装等等.苹果希望解决这样的问题,要保证每一个安装到 iOS 上的 APP 都是经过苹果官方允许的,保证方法就是通过代码签名。
实现原理
iOS代码签名机制
1.基本原理
代码签名的技术基础是数字签名,也就是非对称加密算法。如果我们iOS设备安装APP只通过App Store这一个途径,代码签名的实现就很容易, 在iOS的系统中内置一个公钥,私钥由苹果后台保存,我们传APP到AppStore时,苹果后台用私钥对APP数据进行签名,iOS系统下载这个APP后,用公钥验证这个签名,若签名正确,这个APP肯定是由苹果后台认证的,并且没有被修改过,也就达到了苹果的需求:保证安装的每一个APP都是经过苹果官方允许的。
2.iOS的双层签名机制
实际上iOS应用的安装除了app store,还有开发者调试和企业安装两种形式。对于这两种安装方式,他们具有以下需求
1)安装包不需要上传到App Store,可以直接安装到手机上.
2)苹果为了保证系统的安全性,又必须对安装的APP有绝对的控制权:a.经过苹果允许才可以安装;b.不能被滥用导致非开发APP也能被安装
于是,iOS采用的方案是双层代码签名。
mac系统中有自身的非对称加密的一对公私钥,Xcode即可完成,这里称为公钥M和私钥M;苹果系统里有固定的一对公私钥,私钥在苹果后台,公钥在每个iOS系统里,这里称为公钥A和私钥A。
首先,将公钥M和一些开发者的信息传到苹果后台,这个就是申请证书时用到的CSR文件。苹果后台使用私钥A对公钥M进行签名,得到的数据包包含公钥M和苹果的签名,这个就是发放给开发者的证书。申请证书之后,用户申请appid和Provisioning Profile描述文件,Provisioning Profile包含了证书、授权设备uuid,以及app的权限,同样是经过苹果签名的。
然后在mac上对app开发编译完毕后,用本地的私钥M对这个APP进行签名,同时把从苹果服务器得到的Provisioning Profile文件打包进APP里,文件名为embedded.mobileprovision。
在安装时,iOS系统解压ipa安装包,可以得到embedded.mobileprovision文件,取得证书,通过系统内置的公钥A,去验证证书的数字签名是否正确。验证证书后确保了公钥 M 是苹果认证过的,再用公钥M去验证APP的签名,这里就间接验证了这个APP安装行为是否经过苹果官方允许。
Android签名机制
Android 不同于iOS只能安装app store上的应用,允许随意安装来自第三方的应用,同样也要求开发者为开发的应用进行签名,但证书不需要由证书认证中心签名,使用开发者自制的签名证书。Android 系统不会安装或运行没有正确签名的应用,此规则适用于任何地方运行的Android系统。因此在真机或模拟器上运行或者调试应用前,必须为其设置好签名。签名除了为了保证app的真实性和完整性,还有以下几个好处:
1.应用程序升级 - 当发布应用的更新时,如果想染给用户无缝的升级到新版本,需要继续使用相同的某个或某套证书来签名更新包,当系统安装应用的更新时,它会比较现在的版本和新版本的证书,如果证书吻合,包括证书数据和顺序都吻合,那么系统允许更新,如果新版本所做的签名不是匹配的,那么将需要给用起一个不同的包名 - 在这种情况下,用户相当于安装了一个完全新的程序。
2.用用程序模块化 - Android允许相同证书签名的应用程序运行在相同的进程中,此时系统会将它们作为耽搁应用程序对待,在这种方式中,可以按模块化的凡事部署应用,用户可以根据需要独立的跟新每一个模块。
3.代码、数据的授权共享 - Android提供模式匹配的权限控制机制,因此一个应用可以暴露功能给另一个用指定证书签名的签名的应用,通过用相同证书签名多个应用,以及使用模式匹配的权限检查,应用程序可以以安全的方式共享代码和数据。
两种签名:
1、调试模式下签名(sdk 为应用自动生成一个签名证书,调试模式下签名的应用不能对外发布,因为由构建工具创建的证书是不安全的,应用商店不接受调试证书签名的apk)。这种模式下密钥在不同机器上可能都不一样,如果换了机器进行版本升级将不能覆盖安装。
2、发布模式下签名(需要生成自己的证书)
注:给自己开发的app签名,就代表着我们自己的版权,之后要进行升级,也必须要使用相同的签名才可以,签名代表着自己的身份(即 keystore,是一个包括私人密钥集合的二进制文件),创建的keystore 多个app可以使用同一签名。
签名的原理也是基于非对称加密算法。给apk签名有两种方法,一种是通过命令行,android在公布的源码包中提供了一个工具—signapk.jar,用于进行应用程序的签名,签名命令如下:
java -jar signapk.jar certificate.pem key.pk8 UnsignedApp. apk SignedApp.apk
其中,certificate.pem和key.pk8分别为用于签名的公钥证书和私钥文件;UnsignedApp.apk是未签名的Android应用程序;SignedApp.apk是签名后的Android应用程序。通过对应用程序包(apk为zip压缩文件)解压缩后的数据对比,可以看出签名后的apk包中多了一个目录“/META-INF”,此目录下包含三个文件:MANIFEST.MF、CERT.SF、CERT.RSA。具体的签名过程如图所示,包含5个步骤:
另外一种签名方式是使用ADT Export Wizard,例如在android应用的开发工具android studio里的Generate Signed APK和Project Structure里可以进行进行配置来生成签名,配置好后,项目文件里会自动补全相关代码。
验证机制
Android 系统使用“PackageInstaller”程序进行应用程序的安装,并在安装过程中进行代码签名验证。(1)调用verifySignature() 函数,验证CERT.RSA文件中的签名值确实是从CERT.SF签名得到 ;(2)调用JarVerifier.verify()函数,验证MANIFEST.MF文件的摘要确实同CERT.SF提取的摘要值一致;(3)对包中除了签名数据之外的其它文件调用VerifierEntry.verify()函数,验证文件的摘要值等于MANIFEST.MF中的摘要值。安装后,应用程序每次启动时,android系统也会进行简单的路径和时间戳的验证。
Windows代码签名机制
微软公司在windows平台下设计了一种代码签名机制,并且在64位操作系统的平台下强制性地对涉及到内核的驱动程序进行签名验证。为了避免用户应用程序访问或修改关键的操作系统数据,windows使用了两种处理器访问模式,用户模式和内核模式。微软代码签名机制的策略为:每次驱动程序系统文件被加载到内存中时,代码签名机制会检测被加载到内核中的驱动程序或系统文件是否已经被签名,此规则适用于每个运行内核权限的模块。不仅是普通用户账户,计算机的管理员账户也同样不能加载未签名的代码。