Android 安全团队定期收到关于如何预防 Android 设备上潜在安全问题的咨询。我们偶尔还会抽查设备,并将潜在问题告知设备制造商和受影响的合作伙伴。
此页面根据我们的经验提供安全最佳实践,扩展了我们为开发者提供的 安全设计 文档,并包含针对在设备上构建或安装系统级软件的独特细节。
为了促进这些最佳实践的采纳,Android 安全团队尽可能将测试纳入 Android 兼容性测试套件 (CTS) 和 Android Lint 中。我们鼓励设备实现者贡献测试,以帮助其他 Android 用户(在 root/cts/tests/tests/security/src/android/security/cts
查看安全相关测试)。
开发流程
在您的开发流程和环境中使用以下最佳实践。
审核源代码
源代码审核可以检测范围广泛的安全问题,包括本文档中确定的问题。Android 强烈建议进行手动和自动源代码审核。最佳实践
- 在所有应用代码上使用 Android SDK 运行 Android Lint,并更正任何已识别的问题。
- 应使用自动化工具分析原生代码,该工具可以检测内存管理问题,例如缓冲区溢出和差一错误。
- Android 构建系统支持许多 LLVM Sanitizers,例如 AddressSanitizer 和 UndefinedBehaviorSanitizer,可用于此目的。
使用自动化测试
自动化测试可以检测范围广泛的安全问题,包括下面讨论的几个问题。最佳实践
- CTS 定期更新安全测试;运行最新版本的 CTS 以验证兼容性。
- 在整个开发过程中定期运行 CTS,以尽早发现问题并缩短纠正时间。Android 将 CTS 用作我们自动化构建流程中持续集成的一部分,该流程每天构建多次。
- 设备制造商应自动化接口安全测试,包括使用格式错误输入进行的测试(模糊测试)。
签署系统映像
系统映像的签名对于确定设备的完整性至关重要。最佳实践
- 设备不得使用公钥签名。
- 用于签署设备的密钥应以符合行业标准实践的方式进行管理,以处理敏感密钥,包括提供有限的、可审核访问权限的硬件安全模块 (HSM)。
签署应用 (APK)
应用签名在设备安全中起着重要作用,并用于权限检查以及软件更新。在选择用于签署应用的密钥时,重要的是要考虑应用是仅在单个设备上可用还是在多个设备上通用。最佳实践
- 应用不得使用公钥签名。
- 用于签署应用的密钥应以符合行业标准实践的方式进行管理,以处理敏感密钥,包括提供有限的、可审核访问权限的 HSM。
- 应用不应使用平台密钥签名。
- 具有相同软件包名称的应用不应使用不同的密钥签名。当为不同设备创建应用时,尤其是在使用平台密钥时,通常会发生这种情况。如果应用与设备无关,请在不同设备上使用相同的密钥。如果应用是设备特定的,请为每个设备和密钥创建唯一的软件包名称。
发布应用
Google Play 为设备制造商提供了更新应用的能力,而无需执行完整的系统更新。这可以加快对安全问题的响应和新功能的交付,并提供一种确保您的应用具有唯一软件包名称的方式。最佳实践
- 将您的应用上传到 Google Play,以允许自动更新,而无需完整的无线下载 (OTA) 更新。已上传但未发布的应用用户无法直接下载,但应用仍会更新。以前安装过该应用的用户可以重新安装和/或在其他设备上安装。
- 创建一个与您的公司明确关联的应用软件包名称,例如使用公司商标。
- 设备制造商发布的应用应上传到 Google Play 商店,以避免第三方用户冒用软件包名称。如果设备制造商在设备上安装应用但未在 Play 商店中发布该应用,则其他开发者可能会上传相同的应用,使用相同的软件包名称,并更改应用的元数据。当向用户显示应用时,此不相关的元数据可能会造成混淆。
响应事件
外部各方必须能够就特定于设备的安全问题与设备制造商联系。我们建议创建一个公开可访问的电子邮件地址来管理安全事件。最佳实践
- 创建一个 security@your-company.com 或类似的地址并公开。
- 如果您发现影响 Android 操作系统或来自多家设备制造商的 Android 设备的安全问题,您应该通过提交 安全漏洞报告 与 Android 安全团队联系。
实施产品
实施产品时,请使用以下最佳实践。
隔离 root 进程
Root 进程是提权攻击最频繁的目标,因此减少 root 进程的数量可以降低提权风险。CTS 包括一个信息性测试,列出了 root 进程。最佳实践
- 设备应以 root 身份运行最少的必要代码。如果可能,请使用常规 Android 进程而不是 root 进程。ICS Galaxy Nexus 只有六个 root 进程:vold、inetd、zygote、tf_daemon、ueventd 和 init。如果进程必须在设备上以 root 身份运行,请在 AOSP 功能请求中记录该进程,以便可以公开审查。
- 如果可能,应将 root 代码与不受信任的数据隔离,并通过 IPC 访问。例如,将 root 功能减少到可通过 Binder 访问的小型服务,并使用签名权限将该服务公开给具有低权限或无权限处理网络流量的应用。
- Root 进程不得监听网络套接字。
- Root 进程不得为应用提供通用运行时(例如,Java VM)。
隔离系统应用
通常,预安装的应用不应使用共享的系统 UID 运行。但是,如果应用必须使用系统或其他特权服务的共享 UID,则该应用不应导出任何可由用户安装的第三方应用访问的服务、广播接收器或内容提供程序。最佳实践
- 设备应以系统身份运行最少的必要代码。如果可能,请使用具有自己 UID 的 Android 进程,而不是重用系统 UID。
- 如果可能,应将系统代码与不受信任的数据隔离,并且仅向其他受信任的进程公开 IPC。
- 系统进程不得监听网络套接字。
隔离进程
Android 应用沙盒为应用提供了与其他系统进程(包括 root 进程和调试器)隔离的预期。除非应用和用户专门启用了调试,否则任何应用都不应违反该预期。最佳实践
- 除非使用记录在案的 Android 调试方法,否则 Root 进程不得访问各个应用数据文件夹中的数据。
- 除非使用记录在案的 Android 调试方法,否则 Root 进程不得访问应用的内存。
- 设备不得包含任何访问其他应用或进程的数据或内存的应用。
保护 SUID 文件的安全
新的 setuid 程序不应可由不受信任的程序访问。Setuid 程序经常是漏洞的所在地,这些漏洞可用于获得 root 访问权限,因此应努力将 setuid 程序对不受信任的应用的可用性降至最低。最佳实践
- SUID 进程不得提供可用于规避 Android 安全模型的 shell 或后门。
- SUID 程序不得由任何用户写入。
- SUID 程序不应是全局可读或可执行的。创建一个组,将对 SUID 二进制文件的访问权限限制为该组的成员,并将任何应能够执行 SUID 程序的应用放入该组。
- SUID 程序是用户 root 设备的一个常见来源。为了降低这种风险,SUID 程序不应由 shell 用户执行。
CTS 验证程序包括一个信息性测试,列出了 SUID 文件;根据 CTS 测试,某些 setuid 文件是不允许的。
保护监听套接字的安全
当设备在任何接口上的任何端口上进行监听时,CTS 测试将失败。如果发生故障,Android 会验证是否使用了以下最佳实践
- 设备上不应有任何监听端口。
- 监听端口必须能够无需 OTA 即可禁用。这可以是服务器或用户设备配置更改。
- Root 进程不得监听任何端口。
- 系统 UID 拥有的进程不得监听任何端口。
- 对于使用套接字的本地 IPC,应用必须使用 UNIX 域套接字,且访问权限仅限于组。为 IPC 创建文件描述符,并使其对于特定的 UNIX 组为 +RW。任何客户端应用都必须在该 UNIX 组内。
- 某些具有多个处理器(例如,与应用处理器分离的无线电/调制解调器)的设备使用网络套接字在处理器之间进行通信。在这种情况下,用于处理器间通信的网络套接字必须使用隔离的网络接口,以防止设备上未经授权的应用访问(即,使用
iptables
来防止设备上其他应用访问)。 - 处理监听端口的守护程序必须能够可靠地处理格式错误的数据。Google 可能会使用未经授权的客户端和(如果可能)授权的客户端对端口进行模糊测试。任何崩溃都将作为错误提交,并具有适当的严重程度。
日志数据
日志记录数据会增加数据暴露的风险并降低系统性能。由于默认安装在 Android 设备上的应用记录敏感用户数据,因此发生了多起公共安全事件。最佳实践
- 应用或系统服务不应记录来自第三方应用的数据,这些数据可能包括敏感信息。
- 应用不得记录任何个人身份信息 (PII) 作为正常操作的一部分。
CTS 包括检查系统日志中是否存在潜在敏感信息的测试。
限制目录访问
全局可写目录可能会引入安全漏洞,并使应用能够重命名受信任的文件、替换文件或进行基于符号链接的攻击(攻击者可能会使用指向文件的符号链接来欺骗受信任的程序执行不应执行的操作)。可写目录也可能阻止应用的卸载正确清理与应用关联的所有文件。
作为最佳实践,系统或 root 用户创建的目录不应是全局可写的。CTS 测试通过测试已知目录来帮助强制执行此最佳实践。
保护配置文件的安全
许多驱动程序和服务都依赖于存储在 /system/etc
和 /data
等目录中的配置文件和数据文件。如果特权进程处理这些文件并且这些文件是全局可写的,则应用可能会通过在全局可写文件中制作恶意内容来利用进程中的漏洞。最佳实践
- 特权进程使用的配置文件不应是全局可读的。
- 特权进程使用的配置文件不得是全局可写的。
存储原生代码库
特权设备制造商进程使用的任何代码都必须位于 /vendor
或 /system
中;这些文件系统在启动时以只读方式挂载。作为最佳实践,设备上安装的系统或其他高特权应用使用的库也应位于这些文件系统中。这可以防止安全漏洞,该漏洞可能允许攻击者控制特权进程执行的代码。
限制设备驱动程序访问
只有受信任的代码才能直接访问驱动程序。如果可能,首选架构是提供一个专用守护程序,该守护程序代理对驱动程序的调用,并将驱动程序访问限制为该守护程序。作为最佳实践,驱动程序设备节点不应是全局可读或可写的。CTS 测试通过检查已知的暴露驱动程序实例来帮助强制执行此最佳实践。
禁用 ADB
Android 调试桥 (adb) 是一种有价值的开发和调试工具,但专为在受控、安全的环境中使用而设计,不应启用以供常规使用。最佳实践
- ADB 必须默认禁用。
- ADB 必须要求用户先将其打开,然后才能接受连接。
解锁 Bootloader
许多 Android 设备都支持解锁,使设备所有者能够修改系统分区和/或安装自定义操作系统。常见用例包括安装第三方 ROM 和在设备上执行系统级开发。例如,Google Nexus 设备所有者可以运行 fastboot oem unlock
来启动解锁过程,该过程会向用户显示以下消息
解锁 Bootloader?
如果您解锁 Bootloader,您将能够在此设备上安装自定义操作系统软件。
自定义操作系统未经过与原始操作系统相同的测试,可能会导致您的设备和已安装的应用停止正常工作。
为防止未经授权访问您的个人数据,解锁 Bootloader 还会删除您设备上的所有个人数据(“恢复出厂设置”)。
按音量增大/减小按钮选择“是”或“否”。然后按电源按钮继续。
是:解锁 Bootloader(可能会使保修失效)
否:不解锁 Bootloader 并重启设备。
作为最佳实践,可解锁的 Android 设备在解锁前必须安全地擦除所有用户数据。未能正确删除解锁时的所有数据可能会使物理上接近的攻击者能够未经授权访问机密的 Android 用户数据。为了防止用户数据泄露,支持解锁的设备必须正确实施解锁(我们已经看到许多设备制造商不正确地实施了解锁)。正确实施的解锁过程具有以下属性
- 当用户确认解锁命令时,设备必须立即开始数据擦除。在安全删除完成之前,不得设置
unlocked
标志。 - 如果无法完成安全删除,设备必须保持锁定状态。
- 如果底层块设备支持,应使用
ioctl(BLKSECDISCARD)
或等效命令。对于 eMMC 设备,这意味着使用安全擦除或安全 Trim 命令。对于 eMMC 4.5 及更高版本,这意味着使用正常的 Erase 或 Trim,然后执行 Sanitize 操作。 - 如果底层块设备不支持
BLKSECDISCARD
,则必须改用ioctl(BLKDISCARD)
。在 eMMC 设备上,这是一个正常的 Trim 操作。 - 如果不支持
BLKDISCARD
,则用全零覆盖块设备是可以接受的。 - 最终用户必须可以选择要求在刷写分区之前擦除用户数据。例如,在 Nexus 设备上,这是通过
fastboot oem lock
命令完成的。 - 设备可以通过电子熔丝或类似机制记录设备是否已解锁和/或重新锁定。
这些要求确保在完成解锁操作后销毁所有数据。未能实施这些保护措施被认为是中等程度的安全漏洞。
解锁的设备随后可以使用 fastboot oem lock
命令重新锁定。锁定 Bootloader 为新的自定义操作系统提供与原始设备制造商操作系统相同的用户数据保护(例如,如果设备再次解锁,用户数据将被擦除)。