作为一名 Android 或 iOS 开发者,您可能已经熟悉一些常见的安全开发最佳实践,比如验证外部输入、合理管理内存以及避免使用弱加密算法。然而,即便是最精心编写的代码,也可能包含一些 bug,其中一些可能会导致可被利用的安全漏洞,尤其是在使用 C 或 C++ 等语言编写的原生代码中。
多年来,开发了许多防御技术,可以通过简单的编译器标志来启用,而无需修改源代码。这些技术能够有效地提高应用的安全性。在本文中,我们将为您概述一些关键的安全特性,包括:
· 它们防护的攻击类型
· 如何启用这些特性(步骤指南)
· 它们在 Android 和 iOS 上的适用性
· 如何为不同平台设置编译器标志
为 Android 和 iOS 设置编译器标志
在深入探讨具体的安全特性之前,我们先简要回顾一下如何在 Android 和 iOS 上设置这些编译器标志。如果您已经熟悉这些操作,可以跳过这一部分!
Android
通常,Android 应用的原生代码通过 ndk-build 脚本或结合 Gradle 使用 CMake 进行编译。在 ndk-build 的情况下,可以通过在 Application.mk 文件中添加新的标志来启用:
如果您使用的是 Gradle 配合 CMake,则可以在 build.gradle 文件中添加编译器标志:
iOS
在 iOS 中,您可以通过 Xcode 项目的“Build Settings”选项卡来设置编译器标志:
1. 在“Project Navigator”中选择您的项目文件。
2. 转到目标的“Build Settings”选项卡。
3. 在“Other C Flags”或“Other C++ Flags”部分添加所需的标志。
编译器相关的安全特性
1. 栈保护(Stack Canaries)
栈保护是一种防御缓冲区溢出攻击的基础技术。缓冲区溢出攻击发生时,攻击者通过溢出栈上的缓冲区,可能会覆盖函数的返回地址,从而执行任意代码,造成严重的安全漏洞,例如未经授权的访问或系统崩溃。启用栈保护(通过 -fstack-protector-strong 编译器标志)可以有效避免这类攻击。
· 适用于 Android: ✅
· 适用于 iOS: ✅
如果您想进一步了解该主题,可以查阅 Wikipedia 上关于缓冲区溢出保护的文章,或者阅读经典的《Smashing The Stack For Fun And Profit》一文。
2. 指针认证(Pointer Authentication,PAC)
指针认证(PAC)通过加密签名指针,尤其是返回地址和函数指针,以防止控制流攻击。若指针被篡改,验证失败,攻击将被阻止。这个特性依赖于特定的硬件支持,这可能会使设备的兼容性成为问题。但幸运的是,目前所有支持的 iOS 设备都已支持 PAC,而 Android 编译器会确保只使用在旧设备上不执行任何操作的指令。
· 适用于 Android: ✅
· 适用于 iOS: ✅
如何在 Android 上启用 PAC:
· 使用 ndk-build 时:在每个 Android.mk 文件中设置 LOCAL_BRANCH_PROTECTION := standard
· 使用 Gradle 配合 CMake 时:添加 -mbranch-protection=standard 编译器标志
在 PAC 的基础上,Google 还建议启用控制流完整性(CFI)。您可以在 LLVM 的官方网站上了解更多关于 CFI 的信息。
如何在 iOS 上启用 PAC:
在 Xcode 的构建设置中,将 arm64e 目标添加到“Architectures”部分。由于 Apple 控制硬件和软件,它可以为所有设备提供一致的 PAC 实施,而 Android 平台则需要根据设备硬件特性通过编译器标志来启用 PAC。
更多信息可以参考 Apple 的文章,了解如何为应用启用指针认证。
3. 只读重定位(Relocation Read-Only,RelRO)
RelRO 是一种保护应用免受内存篡改攻击的机制。它通过在初始化完成后将某些内存区域标记为只读来工作。特别是,它可以保护全局偏移表(GOT),该表用于管理应用程序中的动态链接函数。通过将 GOT 和其他关键区域标记为只读,RelRO 可以防止攻击者修改这些指针,从而劫持应用程序的执行流。
· 适用于 Android: ✅
· 适用于 iOS: ❌(iOS 没有 GOT 结构)
RedHat 博客有一篇很好的文章,详细介绍了 RelRO 的更多信息。
确保您的移动应用安全
确保您的应用安全不仅仅是编写安全代码,还需要采取综合措施,包括加强原生代码的构建过程。启用上述提到的编译器标志可以帮助您实现这一目标,降低常见攻击带来的风险,而且不会对性能造成显著影响。然而,建立安全的构建过程并不是一次性的任务,它需要持续的监控。在应用程序不断演进的过程中,确保这些安全配置始终保持有效非常重要。通过将 MAST(移动应用安全测试)工具集成到 CI 流水线中,您可以自动化地测试最终产品的安全性,捕捉构建设置中的回归问题,避免将不安全的应用发布给用户。