Android 本是一个开放、自由的系统。然而,自由带来权力,也带来更多的责任,普通的移动设备用户显然无法承担这些责任。于是,为了保护安全,Android 引入了签名机制。这一机制使得 Android 系统中大部分的自由都给了开发者,也保障了用户最基本的安全。

什么是签名

签名,指的是数字签名。

数字签名的作用与纸质文件的上的签名一样,用于证明某文件确实是指定作者创制的,且具有防修改的特性。其具体内容如下:

  • 签名使用非对称加密算法。
  • 代表一个作者的有两个密钥:私钥和公钥。私钥由作者自行保管,公钥公布于众。
  • 非对称加密基于数学难题。根据私钥可以轻易生成公钥;公钥包含私钥的信息,但难以逆推出私钥。
  • 签名时,作者先计算文件的校验值,然后使用私钥对其进行“解密”操作,得到签名数据,随后将签名和公钥一起附在文件中。
  • 检验签名时,接收者用公钥对签名数据进行“加密”操作,还原成校验值,然后检验其与文件的校验值是否一致。若一致,说明文件确实来自公钥所对应的作者。

一旦文件遭到篡改,文件校验值就会变得与签名数据不符合,这样签名检验无法通过。而第三方没有掌握作者的私钥,因此也无法以作者的名义进行重新签名。

讨论 Android 签名机制时,所谓“签名”通常指的是签名者的公钥,不同的文件“签名相同”表明文件来自同一作者。

应用安装时的签名校验

下文中“包名”是应用的唯一标识符。系统判断两应用是否为同一应用(是否发生覆盖安装),依据是包名是否相同。

应用安装

初次安装应用时,Android 会检测签名是否正确。如果签名不正确或不存在,则不允许安装。

这时,Android 不会关心签名具体是什么,即不关心具体来自什么开发者。然而,有这些特殊情况:

  • 有的系统会建立已知常用应用的签名数据库。若用户选择的安装包签名不符,会发出警告。
  • 大多数涉及敏感数据的应用会有自我签名验证行为,若签名不是来自原厂,则会警告用户或停止工作。然而,理论上这个验证是可以移除的。

应用更新

若安装应用包时,该应用已经存在,则需要满足以下条件才能安装:

  • 新应用包签名与已有应用一致。
  • 新应用包版本不小于已有应用。

应用私有数据

数据的存储位置

Android 系统中,应用将其数据存储在三种位置:

  • 私有数据(/data/data/<包名>/)。此处存储的数据无法被其他应用访问。
  • 外部数据(/sdcard/Android/data/<包名>/)。此处存储的数据可以使用文件管理器查看或备份。申请并获取“存储”权限的应用,可以访问其他应用的外部数据。
  • 公共存储(/sdcard/其他位置 或 外置存储器)。应用必须申请并获取“存储”权限,才能向此处写入数据。任何应用都可以访问这些数据。

其中,私有数据和外部数据会在应用卸载时被系统清除。

私有数据的安全要求

私有数据是神圣之地,是敏感度最高的地方。

要求任何应用均无法访问其他应用的私有数据;如果应用和系统都不具有“可调试”属性(注:只有开发用模拟器和工程机的系统会具有“可调试”属性),即便使用 USB 调试,也无法访问应用私有数据。

还要求处理同一私有数据的应用必须包名相同、签名相同,签名不同的应用绝对不能继承已有的私有数据。

因此,对安全性要求高的应用(如支付宝)通常将用户令牌信息存储于此。单机游戏为了避免用户直接修改进度数据,也会将数据存储在这里。不难看出,有的安全要求确实是为了保护数据安全,有的则是刻意阻止用户修改,保护单机游戏的机制。

私有数据的备份

原生 Android 系统中,若应用具有“可备份”属性(大多数应用具有),则可以通过电脑发送备份命令备份私有数据。备份得到的文件可以拆包。然而,备份文件还携带了应用的签名信息和来自系统的签名,系统并不会允许将其恢复至签名不符的应用或另一设备中。

许多国内定制版系统的数据备份功能所得文件的私有数据部分都会被加密,不允许用户查看和更改。

应用更新的安全要求

应用更新时发生什么?

应用更新,即覆盖安装。相比于全新安装,应用更新有以下特点:

  • 安装的新应用继承已授予原应用的权限。
  • 覆盖安装保留应用的私有数据和外部数据,因此新安装的应用将继承对它们的访问权。

签名机制对私有数据的保护

系统对私有数据把守很严。然而,只要使用更新包覆盖掉原有应用,新的应用就可以访问原应用的的私有数据。如果坏人将一个后门程序伪装为更新包,则可以窃取用户数据。为避免这种情况,系统要求新应用与原应用签名一致,以保证它们来自相同开发者。

此外,坏人还可能诱导用户用已知存在安全漏洞的旧版本覆盖安装应用,并借此窃取应用数据。因此,系统还要求新应用版本号不低于旧版本,防止回滚攻击。

应用共享用户 ID

上文为了叙述方便,均未考虑共享用户 ID 的情况。

应用的 AndroidManifest.xml 文件中有一个称为“共享用户 ID”的属性 sharedUserId。多个应用的此属性相同,则它们为“共用户应用”。共用户应用具有以下特点:

  • 安装新应用时,若系统中已存在它的共用户应用,则新应用的签名必须与其一致,否则无法安装。
  • 共用户应用运行在同一进程中,这可以减少内存消耗。但是它们不会同时崩溃。
  • 共用户应用的私有数据可以互相访问。它们的私有数据仍然分开存储,并不在一起。

另有两个特殊的用户 ID:

  • android.uid.system 表明应用为系统核心应用。具有此 UID 的应用签名必须与 /system/framework/framework-res.apk 一致。
  • android.uid.systemui 表明应用为“系统界面”软件。具有此 UID 的应用应当有且仅有一个。

framework-res.apk 的签名即为系统的“平台签名”。

对应用签名机制的态度

要自由还是要安全?人们对于这一问题的见解不同,因此对应用签名机制也有了不同的态度。

普通用户 - 接受

作为保障安全的重要屏障,普通用户接受这一限制。

要利用好这道屏障,初次安装应用时一定要确保应用来自正规渠道,否则其可能已经携带了非官方的签名。

应用修改者 - 规避

应用修改者包括自行对应用进行逆向工程并修改的开发者,以及使用应用修改器修改游戏(多为单机小游戏)的用户。由于签名机制会阻碍第三方修改,这类用户会规避签名机制的限制。

初次安装可能未来需要修改的应用时,他们将会用自己的证书重新签名再安装,以确保签名始终掌握在自己手中。后续新版的游戏或自己制作的修改版只要使用自己的证书再次签名,就能正常覆盖安装。

部分高级用户 - 接受并利用

高级用户,即常说的“Android 玩家”。此类用户的设备一般具有 Root 权限。

由于 Root 权限的存在,此类用户可以任意导出、导入和修改应用的私有数据,签名机制已经不会造成过大的不便。正常情况下,他们让签名机制保护自己,特殊情况时,他们则利用文件管理器破例操作私有数据文件,达成自己的目的。

部分高级用户 - 全盘否定

由于正常 Android 设备都具有应用签名限制,事实上伪造签名进行的后门应用攻击已经少之又少。

为了方便应用修改与破解的工作,有的高级用户不惜牺牲安全性(一般很少在主力手机上这么干)来换取便利,直接通过修改系统的方法彻底移除签名机制的限制(常称为“Android 核心破解”,幸运破解器等应用在已 Root 设备上会提供这项功能)。由于这样的破解会一并移除签名验证,使得系统认为一切签名有效,他们也可以使用伪造签名的方法绕过应用的自我签名验证,而无须破解自我签名验证再实施修改。

系统更新包签名

使用原厂 Recovery 系统更新 Android 系统时,为保证新的系统来自原厂,会使用与应用更新相似的签名限制。此处不做赘述。

封面图像使用图标:Lock Icon by Chamestudio


undefined