客户端安全(签名)

安卓开发的同学知道,安卓APP在发布时候,都要签名一下。但是,签名到底是什么意思?有啥用呢?

一、签名的普遍意义

在https通信中,有SSL/STL证书,证书里面就有签名。那里的签名,用于保障数据传输的安全。其实,签名不仅仅可以用于保障数据传输安全,一切发生“传递”过程的行为,都可以使用签名确保安全,也就是,签名机制可用于一切传递过程以确保目标物在收到时是“货真价实”的。

关于安卓的签名机制,下面用SSL/STL证书做类比:

SSL/STL证书的签名机制应用过程A:

客户端 <———— SSL/STL证书(含签名机制)<———— 服务端

安卓应用的签名机制应用过程B:

用户手机<————安卓应用(含签名机制)<————应用开发者

过程A,服务端的数据经过N个网关节点,最终到达客户端。客户端应用签名机制校验证书的真实性,即该证书是不是可信任的。

过程B,应用开发者发布应用后,经过各种渠道比如应用市场或者链接下载,最终到达用户手机上。手机操作系统应用签名机制校验应用的真实性,即该应用是不是可信任的。

所以,安卓签名就是本质上跟SSL/STL证书上的签名,发挥着同样的作用,都是确保被签名的东西在“传递”过程中没被篡改,到达目的地时候是货真价实的。

推而广之,其他一切签名机制,比如U盾、水印防伪、区块链等等,也是类似道理。

那么,什么是签名呢?简单而言,就是摘要加密。摘要在一些场景也叫指纹,就是MD5/SHA1/SHA256这些东西,代表着信息的缩影,或者说是信息的ID;加密一般采用非对称加密,私钥往往是在签名人的手中,唯有签名人(或者签名人公开的密钥)才能解密。以此达到“只有我自己才能通关”的目的,从而确定“这个东西没错就是我的”。

二、安卓的签名

安卓的签名,同样具备签名的普遍意义。但是,签名方案有自己一套。这套方案的核心逻辑就是:

1、定一套签名规则,用以保障APP在传递过程中是安全的;

2、再定一套规则,用来保护签名规则的安全(如果签名规则太容易破解,那么APP传递也不安全)。

目前,安卓签名经历了V1\V2\V3共三个版本,其中V1到V2是革命性升级,V2到V3是改良型升级。下面逐一介绍:

(一)V1签名

采用V1签名,应用包的META-INFO/会多出几个文件(XXXX随便改,只要相同即可,关键是后缀名不能变):

Manifest.MF

XXXX.SF

XXXX.RSA

他们的关系是:

MF:APP的每一个文件,对应地生成一条摘要,这些摘要集合可以看成是APP所有文件的摘要,即MF代表着APP的摘要;

SF:MF文件的摘要 + MF文件内每一条摘要记录的摘要(相当于APP文件的二次摘要);

RSA:本质上就是一份非标的、自签发的X509证书 + SF摘要的签名(采用开发者的私钥加密,采用根证书的公钥解密)。该X509证书将后缀名.RSA改成.p7b,即可在windows双击打开XXXX.p7b:

除此之外,还可以用openssl和keytool查看:

>openssl pkcs7 -inform DER -in XXXX.RSA -noout -print_certs -text

 >keytool -printcert -file XXXX.RSA

解释一下几个重点:

1、非标的:所谓标准的证书,一般尾部的签名,其加密对象是对证书内容部分关键信息比如公钥的摘要,比如SSL/STL证书。但是.RSA文件则并非如此,前面部分的内容符合证书TBS域(即基本信息),但是尾部的签名(Signature Algorithm:SHA256withRSAEncryption下面内容),其加密对象含非证书内容的摘要,这个摘要就是SF文件的摘要。

2、自签发的、根证书:证书上的公钥即可解密签名。

3、MF/SF文件只是摘要,不涉及私钥加密;RSA才涉及私钥加密。

所以,V1签名机制核心逻辑是:

RSA文件  ——(保护)——> SF文件 ——(保护)——> MF文件  ——(保护)——>  APP文件

(签名文件 ——(保护)——> APP摘要 ——(保护)——> APP缩影  ——(保护)——>  APP原文)

1、只要RSA文件安全不被破解,那么APP文件就不会被篡改,从而保障APP文件的安全。

2、RSA文件的安全由证书签名机制保障。

这两点,分别对应签名所述核心逻辑:

1、定一套签名规则,用以保障APP在传递过程中是安全的;

2、再定一套规则,用来保护签名规则的安全(如果签名规则太容易破解,那么APP传递也不安全)。

APP安装时候,操作系统执行校验。校验则跟保护顺序相反,关键是操作系统取出公钥解密RSA文件,逆序校验,在此不多说。

(二)V2签名

V2的出现,肯定是V1存在不足。那么V1有哪些不足呢?前面一直在强调APP文件,是的,这就是它的保护范围。但是APP包,可不止APP文件这些东西,还有其他一些东西,比如:

1、META-INFO目录下的文件(这部分不受V1保护);

2、APP包即APK,本质是ZIP文件,ZIP格式中的一些域比如注释内容(不受V1保护);

      ZIP文件的格式如下:

3、 最关键的一条,就是签名后居然还能对APK执行修改,比如字节对齐。

总之,V1的保护范围还不全,存在一些”藏污纳垢”之地,这些地方可以被恶意利用。

另外,从V1的保护机制可以看出,操作系统需要解压缩APK包后,逐个文件计算摘要,所以校验速度也较慢(影响安装速度)。

所以基于以下两点原因,诞生了V2:

1、V1保护范围不足;

2、V1校验速度较慢。

那么,V2是如何改善的呢?V2不再仅仅针对文件了,而是针对整个APK包进行保护,保护逻辑跟V1类似:

1、 算出整个APK包的摘要;

2、对摘要进行加密签名;

3、找个地方存放摘要+签名(这点最有创意);

4、然后立一些规则保护签名。

其中第3点最有创意,因为不是像V1那样存储在固定目录文件META-INFO上,而是在打包后的ZIP包上通过寻址(不是写文件,所以也就没有META-INFO那些签名文件了)开辟一块区域存储,这块区域也叫签名块。

先来看看ZIP的分区:

通过图很清晰看到,就是把签名块插入在1和3直接,这个是通过寻址写入的,而不是普通的文件写入。这样就能达到保护1、3、4所有内容(也就是签名前的APK所有内容)的目的。那么,2分块本身保护范围又如何呢?会不会像V1的META-INFO那样也不受保护成为藏污纳垢之地?下面重点分析一下签名块内容,看看是怎样一种保护状态。

V2的格式:

 其中Digest是整个APK的签名之前的摘要,该摘要和开发者的X509证书以及键值对都会被签名保护,然后公钥又是不能改的,所以在保护范围上基本上就做到“天衣无缝”般地保护了。为啥说是基本上呢,因为这里有一条缝隙逃出了,具体下面漏洞章节分析。 校验时候,用公钥解密签名得到signed data期待的摘要,然后计算signed data真正的摘要,进行比对。

这里重点说上面的1和4点:

第1点:APK包摘要的计算,采用分块分层并行计算(大大提高了校验速度),得到APK包最终的digest(即以下根节点):

APK 摘要

 第4点:立一些规则保护签名。上图V2提到两个地方包含Signature Algorithm ID,也就是算法备份,就是为了防止算法被删除(黑客往往会删除最严格的算法,而采用较宽松的算法进行校验)。另外,V1和V2是可以同时存在的,也就是说可以对APP同时进行V1和V2签名。为了防止黑客将V2签名块删除而回落到V1执行校验,V2签名机制规定:在V1签名文档META-INFO/XXXX.SF文件中(在V1中,该文件受XXXX.RSA文件包含),要有一条V2记录(如下图),因此就无法通过删除V2签名块进行签名版本回落操作。

(三)V3签名

V3签名采用跟V2基本相同的格式,只是增加密钥轮换,目的是在APP包更新过程中能够更改其签名密钥。V3签名会在签名信息中携带历史证书链,安装时候系统通过历史证书链校验即可安装(即允许最新APP签名与已安装的APP签名不同)。V3的格式:

(四)签名校验次序

因为V2/V3均涉及签名块,所以这里说明一下签名块(如下图)。签名块是通过寻址定位的,通过锁定分块长度字段(两个值一样的)来确定签名块的ID-VALUE。

V2/V3数据块本身的存储位置:

V2 的数据块信息存放在 ID = 0x7109871a 的签名块中,

V3 的数据块信息存放在 ID = 0xf05368c0 的签名块中。

校验时候规则是向后/向下兼容的,优先找V3签名块,没有再找V2签名块,没有再采用V1签名机制校验。

APK 签名验证过程

各版本支持情况:

android 7.0 以下:V1

android 7.0 以上:V2

android 9.0 以上:V3

但是,安卓支持多个签名并存(解决向下兼容性问题),所以签名一般建议都勾选,操作系统会自己选择最佳签名版本。

三、安卓签名的漏洞

所谓的漏洞,其实就是利用未保护的“藏污纳垢”之地为非作歹。

(一)V1签名的漏洞

V1藏污纳垢的地方上面已经阐述,主要是:

1、META-INFO目录下的文件(这部分不受V1保护);

2、APP包即APK,本质是ZIP文件,ZIP格式中的一些域比如注释内容(不受V1保护);

3、最关键的一条,就是签名后居然还能对APK执行修改。

已知的一些漏洞就是利用这些特点进行攻克,比如著名的Janus漏洞就是利用签名后还能修改zip信息进行的攻击,还有其他一些类似漏洞比如“9695860”、“9950697”等漏洞。这些漏洞在V2都能被堵住。

另外,一些黑科技技术比如渠道包快速生成比如美团开源项目walle V1(渠道包打包),就是利用META-INFO目录没有被保护,在二次打包过程中植入渠道号,在RUNTIME时候获取渠道号,实现快速打包和渠道号获取。

(二)V2签名的漏洞

V2藏污纳垢的地方就是上面提到的那条“天衣无缝”之外的缝,什么缝呢?就是KEY-VALUE那里,看似被签名保护,但是实际上在校验时候是这样的:通过查找ID为0x7109871a的value来获取APK Signature Scheme v2 Block,对其他的ID选择了忽略。所以,其他ID场景便是这条缝!可以利用这个缝隙做一些事情。比如美团开源项目walle V2(渠道包打包) ,就是利用其他ID未校验植入渠道号,在RUNTIME时候获取渠道号,实现快速打包和渠道号获取。但是要注意,waller V2不支持加固,一旦加固则失效(因为加固也会修改签名块)

(三)V3签名的漏洞

暂未发现

(四)V1/V2/V3签名普遍的漏洞

无论哪一种APP签名,其实都跟SSL/STL证书签名一样,逃不过一种叫“中间人攻击”,而中间人攻击最核心的操作是:调包证书/公钥。APP也存在,比如用户删除掉原来的所有签名,重新签名APP(类比SSL/STL操作,就是过滤服务端证书签名,用中间人自己的证书签名发给客户端)。这种场景下,APP首次是可以安装成功的,然后,如果后续收到官方的APP,反而会因为签名不一致无法升级成功,让假冒APP先入为主了。

另外,签名也只是保护静态包安全,对于安装之后处于runtime的应用安全,则是束手无策了(本来就不是签名职责保护范围了)。

所以,签名本身并不能解决所有APP的安全问题,还需要借助其他一些技术,比如编码安全,比如加固等。

四、安卓签名的扩展价值

1、操作系统签名扩展应用

操作系统除了在安装时候校验签名外,在安卓系统运行过程中,同一个签名的不同应用,操作系统会视它们为同一个开发者的应用,在进程上就是同一个进程,一些操作和标识也是共享的。

2、第三方签名扩展应用

在安卓应用申请第三方账号时比如微信分享/百度地图这种,第三方一般会要求提供这样的信息:谁的哪个应用?

谁的:其实就是签名信息,一般用签名的指纹(在XXXX.RSA里,有MD5/SHA1/SHA256等指纹)

哪个:一般就是包名,比如com.qq.music

参考文章
https://www.jianshu.com/p/308515c94dc6
https://cloud.tencent.com/developer/article/1424865
https://cloud.tencent.com/developer/article/1006237
https://source.android.google.cn/security/apksigning/v2
https://www.cnblogs.com/hongcq/p/6043561.html

V1/V2源码
https://www.jianshu.com/p/dc320629bf9d
https://blog.csdn.net/qq_15827013/article/details/97630787

V1/V2多渠道打包
https://www.jianshu.com/p/332525b09a88?appinstall=0
https://tech.meituan.com/2017/01/13/android-apk-v2-signature-scheme.html
https://github.com/Meituan-Dianping/walle


版权声明:本文为AutumnGingkgo原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。