移动应用安全备忘录¶
与 Web 应用和其他形式的软件相比,移动应用开发带来了一些独特的安全挑战。本备忘录提供了移动应用开发中安全考虑的指导。它绝不是一份全面的指南,而是为开发人员在移动应用开发中考虑安全性提供一个起点。
架构与设计¶
1. 安全设计¶
- 在开发之初就选择安全设计,而不是事后才考虑。
- 牢记最小权限、深度防御和关注点分离等安全原则。
- 遵循行业标准和最佳实践,例如
- 美国国家标准与技术研究院 (NIST)
- 互联网工程任务组 (IETF)
更多信息,请参阅安全产品设计备忘录。
2. 安全 API¶
- 确保您的移动应用与后端服务安全通信。
- 使用 OAuth2、JWT 或类似机制进行安全认证。
- 定期更新和轮换任何使用的 API 密钥或令牌。
3. 最小权限原则¶
- 仅请求您的应用所需的权限。
- 这不仅适用于用户授予的设备权限,也适用于后端服务授予应用的权限。
- 避免存储权限过于宽松的应用文件。
- 默认安全:应用应默认具有最安全设置。
4. 供应链¶
使用第三方库和组件进行开发可能会引入安全未知风险。
- 确保应用签名。
- 只使用受信任和经过验证的第三方库和组件。
- 为应用更新、补丁和发布建立安全控制。
- 监控和检测所用第三方产品的安全事件。
有关发现漏洞时管理第三方依赖项的建议,请参阅漏洞依赖管理备忘录。
认证与授权¶
认证是一个复杂的主题,存在许多陷阱。认证逻辑必须极其谨慎地编写和测试。这里的提示只是一个起点,仅触及皮毛。更多信息,请参阅认证备忘录以及 OWASP 移动应用安全十大风险中的M1:不安全认证/授权。
1. 不要信任客户端¶
- 在服务器端执行认证/授权,并在成功认证后才将数据加载到设备上。
- 如果将数据存储在本地,请使用从用户登录凭证派生的密钥对其进行加密。
- 不要在设备上存储用户密码;使用可撤销的设备特定令牌。
- 避免使用可伪造的值(如设备标识符)进行认证。
- 假设所有客户端控制都可以被绕过,并在服务器端也执行它们。
- 包含客户端代码以检测代码/二进制篡改。
2. 凭证处理¶
- 不要在移动应用中硬编码凭证。
- 传输中加密凭证。
- 不要在设备上存储用户凭证。考虑使用安全的、可撤销的访问令牌。
3. 密码和 PIN 策略¶
- 要求密码复杂度。
- 不允许短 PIN,例如 4 位数字。
- 使用平台特定的安全存储机制,例如 Keychain (iOS) 或 Keystore (Android)。
4. 生物识别认证¶
- 使用平台支持的生物识别认证方法。
- 始终提供一个备用方案,例如 PIN。
5. 会话管理¶
- 会话应在不活动后超时。
- 提供远程注销功能。
- 使用随机生成的会话令牌。
- 安全会话数据,包括客户端和服务器端。
6. 令牌存储¶
- 安全存储认证令牌。
- 优雅地处理令牌过期。
7. 敏感操作¶
- 对于更改密码或更新支付信息等敏感操作,要求用户重新认证。
- 在显示高度敏感信息之前,也考虑要求重新认证。
- 对任何后端功能要求授权检查。
数据存储与隐私¶
1. 数据加密¶
- 对静态数据和传输中的敏感数据进行加密。
- 将私有数据存储在设备的内部存储中。
- 使用平台 API 进行加密。不要尝试实现自己的加密算法。
- 尽可能利用基于硬件的安全功能(例如,iOS 上的 Secure Enclave,Android 上的 Strongbox)进行密钥存储和加密操作。
2. 数据泄露¶
- 注意缓存、日志记录和后台快照。确保敏感数据不会通过这些机制泄露。
有关不应记录的数据示例,请参阅日志备忘录。
3. 使用 HTTPS¶
- 始终使用 HTTPS 进行网络通信。
4. 第三方库¶
- 确保所有第三方库都是安全的并保持最新。
5. 个人身份信息 (PII)¶
- 将任何 PII 最小化到必需程度。
- 如果可能,尝试用不那么关键的信息替换 PII。
- 减少 PII,例如减少位置更新频率。
- 实施 PII 的自动过期和删除,以最大限度地减少保留。
- 在收集或使用 PII 之前征得用户同意。
网络通信¶
1. 不要信任网络¶
- 假设所有网络通信都是不安全的,并且可能被截获。
2. 使用安全协议¶
- 所有网络通信都使用 HTTPS。
- 不要覆盖 SSL 证书验证以允许自签名或无效证书。
- 避免混合版本 SSL 会话。
- 即使通过 SSL 发送数据,也要加密,以防将来出现 SSL 漏洞。
- 使用强大的、行业标准的密码套件,并具有适当的密钥长度。
- 使用受信任 CA 提供商签名的证书
- 避免通过短信发送敏感数据。
3. 证书绑定¶
- 考虑证书绑定。有关此方法的优缺点,请参阅绑定备忘录。
用户界面¶
1. UI 数据遮罩¶
- 在 UI 字段上遮罩敏感信息,以防止“搭肩偷窥”。
2. 用户通知¶
- 通知用户与安全相关的活动,例如来自新设备的登录。
3. 输入验证¶
- 验证和清理用户输入。更多信息,请参阅输入验证备忘录。
4. 输出验证¶
- 验证和清理输出,以防止注入和执行攻击。
代码质量¶
1. 静态分析¶
- 使用静态分析工具识别漏洞。
2. 代码审查¶
- 在代码审查期间将安全性作为重点。
3. 更新库¶
- 保持所有库最新,以修补已知漏洞。
应用完整性¶
- 禁用调试。
- 包含用于验证应用代码完整性的代码。
- 混淆应用二进制文件。
- 实施运行时反篡改控制。
- 检查调试、钩子或代码注入的迹象。
- 检测应用是否在模拟器或已 Root/越狱设备上运行。
- 在运行时验证应用签名。
- 对检测到的篡改应用适当的响应(例如,限制功能)。
测试¶
1. 渗透测试¶
- 执行道德黑客攻击以识别漏洞。
- 测试示例
- 密码学漏洞评估。
- 尝试通过从 POST/GET 请求中移除任何会话令牌来匿名执行后端服务器功能。
2. 自动化测试¶
- 利用自动化测试确保安全功能按预期工作并且访问控制得到执行。
3. 可用性测试¶
- 确保安全功能不会损害可用性,这可能导致用户绕过安全功能。
部署后¶
1. 事件响应¶
- 制定清晰的事件响应计划。
2. 更新¶
-
计划定期更新和补丁。对于移动应用而言,这尤为重要,因为补丁发布与用户实际收到更新版本之间存在延迟,这取决于应用商店的审核流程以及用户更新应用所需的时间。
-
必要时使用强制用户更新其应用版本的机制。
3. 监控和分析¶
- 使用实时监控来检测和响应威胁。
平台特定指南¶
安卓¶
- 使用 Android 的 ProGuard 进行代码混淆。
- 避免在 SharedPreferences 中存储敏感数据。有关安全处理数据的更多详细信息,请参阅 Android 文档。
-
禁用备份模式以防止敏感数据存储在备份中。
-
使用带有硬件支持(TEE 或 StrongBox)的 Android Keystore 安全存储加密密钥。
- 方法:在
KeyGenParameterSpec.Builder
中指定.setIsStrongBoxBacked(true)
(如果可用,Android 9+)来生成带有硬件支持的密钥。 - 通过
KeyInfo.isInsideSecureHardware()
验证硬件支持的存储。 - 如果 Strongbox 不可用,则回退到常规的硬件支持的密钥库。
- 使用
.setUserAuthenticationRequired(true)
为敏感操作配置密钥使用限制。 - 请参阅硬件支持的密钥库文档。
- 方法:在
-
实施 Google 的 Play Integrity API 以进行设备和应用完整性检查。
- 方法:从设备获取完整性判断,在服务器端验证,并在完整性检查失败时采取行动。
- SafetyNet Attestation API 已于 2025 年 1 月完全关闭。所有开发人员必须迁移到 Play Integrity API。
- 请参阅Play Integrity API 文档。
iOS 和 iPadOS¶
快捷指令权限¶
-
iOS/iPadOS 快捷指令允许自动化应用功能,即使设备锁定时也可能启用敏感操作。
-
用户可以在设备锁定时执行快捷指令的几种情况:
- 如果将快捷指令添加为“今天”视图的小组件,则可以在设备锁定时访问和执行它。
- 如果将快捷指令分配给操作按钮(在 iPhone 15 Pro 和 iPhone 16 Pro 机型上),则可以在设备锁定时按下操作按钮来执行它。
- 如果将快捷指令分配给控制中心(在 iOS/iPadOS 18+ 上),则可以在设备锁定时拉起控制中心并按下快捷指令按钮来执行它。
- 可以在设备锁定时通过 Siri 调用快捷指令。
- 如果将快捷指令添加到用户的主屏幕(在 iOS/iPadOS 18+ 上),则可以在设备锁定时通过点击用户锁定屏幕上的快捷指令按钮直接执行它。
- 如果快捷指令设置为按特定间隔或特定时间运行,即使设备锁定,它也可以执行。
-
通过快捷指令触发的敏感应用功能应始终要求设备解锁才能执行。
-
方法:在 Keychain 中存储安全令牌,应用在执行敏感快捷指令之前会验证这些令牌。使用
UIApplication.shared.isProtectedDataAvailable
实施检查,以在设备锁定时限制敏感操作的执行。
Siri 权限¶
- Siri 可以通过语音或键入与 Siri 对话命令访问应用功能,默认情况下,即使设备锁定时也可以访问,这可能导致未经授权的操作。
- 方法:将暴露敏感信息或功能的意图的
requiresUserAuthentication
设置为true
。此外,对于需要明确用户确认的操作,设置INIntent.userConfirmationRequired = true
。这些设置确保 Siri 在执行敏感命令之前进行适当的认证(例如,面容 ID 或 PIN)和明确的批准。(更多信息,请参阅 Apple Developer 的 SiriKit 文档。)
深度链接安全¶
- 深度链接提供直接访问特定应用屏幕的功能,如果未妥善保护,可能会绕过认证,从而允许未经授权的用户访问应用的安全部分。
- iOS 版 Microsoft Authenticator(已于 2024 年 7 月修复)曾出现过一个例子,允许用户通过简单地导航到
msauth://microsoft.aad.brokerplugin/?
来绕过应用锁定,这将打开 Authenticator 并关闭面容 ID/触控 ID/密码提示。 - 方法:对通过深度链接访问的任何视图控制器或端点实施认证检查。使用 apple-app-site-association 文件配置和验证通用链接以实现安全深度链接。清理和验证通过深度链接接收的所有参数,以防止注入攻击。确保未经授权的用户被重定向到登录屏幕,防止在没有适当认证的情况下直接访问应用的敏感部分。(更多信息,请参阅 Apple Developer 的 在您的应用中支持通用链接文档。)
WidgetKit 安全¶
- 锁定屏幕上的小组件可能会显示敏感数据,可能在设备未解锁的情况下将其暴露。
- 方法:对于 iOS/iPadOS 17 及更高版本,使用
WidgetInfo.isLocked
检测锁定屏幕状态。对于更早的 iOS 版本,根据可用的小组件状态实现自定义逻辑,因为仅widgetFamily
不直接提供锁定屏幕信息。在未满足适当安全条件时,应用条件逻辑来遮罩或限制敏感小组件内容。(更多信息,请参阅 Apple 的 WidgetKit 安全。)
额外安全考虑¶
- 配置适当的后台刷新策略,以防止设备锁定时敏感数据更新。
- 在
Info.plist
中为需要用户权限的功能实施适当的隐私相关配置。 - 在应用和小组件之间共享数据时,使用具有适当安全配置的 App Groups。
- 使用 ATS (App Transport Security) 来强制执行严格的网络通信安全策略。
-
不要将敏感数据存储在
plist
文件中。 -
使用 Apple 的 Secure Enclave 进行安全加密密钥存储和敏感操作。
- 方法:使用
SecKeyCreateRandomKey
并将kSecAttrTokenID
设置为kSecAttrTokenIDSecureEnclave
来创建密钥。 - 在 Secure Enclave 中创建的密钥永远不会离开安全硬件——只有使用这些密钥的操作在那里执行。
- 对于生物识别操作,使用
LAContext
和evaluatePolicy
直接通过 Secure Enclave 执行认证,而不会将生物识别数据暴露给您的应用。 - 考虑访问控制选项,如
kSecAccessControlBiometryAny
或kSecAccessControlUserPresence
,以在密钥使用前要求用户认证。 - 请参阅Secure Enclave 文档。
- 方法:使用
-
使用 Apple 的 App Attest API (iOS 14+) 验证应用完整性。
- 方法:使用
DCAppAttestService
生成认证密钥和断言,并在服务器端验证断言。 - 配合使用 Apple 的 DeviceCheck API 进行持久设备状态跟踪。
- 请参阅App Attest 文档。
- 方法:使用
高级硬件安全与监控¶
- 现代设备通常提供可信执行环境 (TEE) 或安全硬件模块。通过标准操作系统 API 利用这些功能。
- 在更高风险场景中,考虑额外的运行时安全措施(行为异常检测、运行时监控)以补充内置操作系统保护。
欲了解更多信息,请访问OWASP 移动应用安全十大风险项目。有关更详细的移动安全框架,请参阅OWASP 移动应用安全项目。