Flutter 应用安全检查清单
阶段 0:治理、环境与 CI/CD
工具与版本
- 保持 Flutter、Dart SDK、Android Studio/Xcode 以及所有插件/依赖项为最新版本。
- 在每次发布前,审查 Flutter 软件包和原生 SDK 的安全通告。
强制执行 CI 门禁
- 在每次 PR 时运行:
-
dart analyze -
flutter test --coverage - Android/Gradle lint
- iOS 构建检查
- 依赖项审计
- 在分析器报错以及任何配置为错误的告警时中断构建。
- 在发布分支上强制实现零 lint 错误。
建立安全门禁
- 在每次 PR 和发布前运行移动端 SAST/SCA/DAST 扫描。
- 阻断高危(High)/严重(Critical)漏洞。
- 将扫描直接集成到 CI/CD 中,以便高危/严重发现使流水线失败。
机密信息处理
- 确保以下位置不包含任何机密信息:
- Dart 源码
- 原生代码
-
AndroidManifest.xml -
Info.plist - 静态资源
- 日志
- 使用环境变量、CI 机密存储和/或机密管理器。
- 在分析和日志记录中脱敏机密信息。
- 定期轮换 API 密钥/令牌,并在怀疑发生泄露时立即轮换。
审计证据与可追溯性
- 为每个构建产物生成并归档:
- 扫描报告
- SBOM
- 构建日志
- 测试报告
- 发布说明
阶段 1:威胁建模、数据分类与资产清单
- 对数据类型进行分类(PII、凭据、令牌、支付数据、健康数据)。
- 记录各类数据在以下位置的收集、处理、存储和传输情况:
- Flutter 应用代码
- 原生层
- 识别信任边界:
- Flutter 应用代码
- 原生平台通道(Android/iOS)
- 设备存储
- WebView/浏览器
- 后端 API
- 第三方服务
- 清点所有 Dart 软件包、插件和原生 SDK。
- 优先使用维护良好、经代码签名且遵循最小权限原则的依赖项。
- 最大限度缩减总依赖数量和作用域。
- 按风险等级定义安全验收标准(例如:“静态敏感数据不得明文存储”、“所有认证流量必须进行证书绑定”、“发布版本中禁止包含调试日志”)。
阶段 2:构建与配置加固(Flutter + Android + iOS)
Flutter 正式发布构建
- Android 使用代码混淆并拆分调试符号构建:
-
flutter build appbundle --release --obfuscate --split-debug-info=build/symbols - iOS 使用代码混淆并拆分调试符号构建:
-
flutter build ipa --release --obfuscate --split-debug-info=build/symbols - 在服务端安全存储
build/symbols。 - 切勿在应用安装包中附带符号文件或映射文件。
日志规范
- 使用
kReleaseMode或等效机制守卫日志输出。 - 从生产代码路径中移除
print/debugPrint/ 详细日志记录。 - 添加 CI 检查,当发布分支的非测试代码中出现调试日志时中断构建。
Android(Gradle + 清单文件)
- 在发布版本中启用 R8/ProGuard 及资源缩减:
-
minifyEnabled true -
shrinkResources true - 使用经过优化的 ProGuard 规则。
- 加固
AndroidManifest.xml: - 发布版本中设置
android:debuggable="false"。 - 设置
android:allowBackup="false",除非具备安全备份设计。 - 设置
android:usesCleartextTraffic="false";生产环境中严禁回退至 HTTP。 - 对组件显式配置
android:exported;避免在缺乏严格权限保护的情况下导出组件。 - 配置网络安全配置(Network Security Config):
- 全局禁用明文流量。
- 定义域名配置。
- 若使用证书绑定,定义包含备用 Pin 的 Pin 集合。
- 签名与完整性:
- 在适用情况下使用 Play App Signing。
- 保护密钥库。
- 启用 Play Integrity API 并将检测信号集成至后端风险决策中。
iOS(Flutter 项目内的 Xcode + Info.plist)
- App Transport Security (ATS):
-
NSAllowsArbitraryLoads = false。 - 仅针对必要的、有明确时间限制的例外情况使用严格的
NSExceptionDomains。 - 发布构建设置:
- 剥离符号。
- 启用无用代码剔除。
- 启用全模块优化。
- 确保发布构建中不存在
DEBUG标志或测试库。 - 原生/插件存储的 Keychain 默认设置:
- 尽可能优先使用
ThisDeviceOnly类型。 - 在应用进入后台时遮罩快照(通过原生或 Flutter 插件),确保任务切换器中绝不显示敏感数据。
阶段 3:网络安全与 TLS/证书绑定
HTTPS/TLS 强制执行
- 确保所有 API 流量均使用 HTTPS/TLS 1.2+。
- 拒绝无效证书、自签名证书(未明确信任时)以及主机名不匹配的端点。
- 配置合理的超时时间。
- 在适当时实现带抖动的重试机制。
- 在 TLS 发生错误时始终保持“故障关闭”(绝不降级至 HTTP)。
证书绑定
- 针对关键域名,在以下位置实现证书或 SPKI SHA-256 绑定:
- Flutter 所使用的 HTTP 客户端。
- 插件所使用的任何原生网络层。
- 为每个主机维护至少一个备用 Pin。
- 设计并测试 Pin 轮换场景。
- 在以下场景下验证证书绑定行为:
- 中间人攻击(MITM)尝试。
- 证书过期。
- 不受信任的 CA。
- 记录 Pin 校验失败日志并上报遥测数据。
服务端安全
- 在后端端点上强制执行 HSTS。
- 使用强密码套件和现代协议版本。
- 对通过 WebView 或应用内浏览器访问的 Web 端点使用 Secure、HttpOnly、SameSite Cookie。
- 避免在客户端保留长期有效的 Bearer 令牌。
阶段 4:本地存储与机密处理
机密信息与令牌
- 切勿将机密信息/令牌存储在:
-
SharedPreferences -
plist文件 - 未加密的 SQLite
- Dart 的明文文件中
- 禁止将机密信息嵌入到:
-
const常量值 - 静态资源
- 自动生成的代码中
安全存储
- 针对令牌和密钥,使用与平台密钥库绑定的安全存储(例如通过 Flutter 插件使用 Android Keystore、iOS Keychain)。
- 在用户体验允许的情况下,对高风险密钥的解密/使用增加生物识别或系统锁屏密码门禁。
- 对于高价值令牌,优先使用设备绑定密钥(
ThisDeviceOnly/ 硬件安全芯片支持)。
加密存储(文件/数据库)
- 针对敏感数据记录,使用加密 SQLite 或等效的文件加密。
- 确保缓存层(例如 HTTP 缓存、本地持久化)不会以明文形式存储 PII 或机密信息。
数据生命周期
- 在注销登出和账号移除时,清除:
- 缓存
- 安全存储项
- 内存中的敏感对象
- 在完成认证流程或高风险会话后,清空 WebView 或应用内浏览器的数据。
- 配置 Android/iOS 备份规则,防止敏感应用数据以未加密形式被系统备份。
阶段 5:隐私保护(UI、剪贴板、屏幕截图)
- 当应用进入后台或处于任务切换器时遮罩 Flutter 敏感屏幕:
- Android 上使用
FLAG_SECURE。 - iOS 上使用快照遮罩。
- 对于高度敏感的界面(例如完整卡号、机密信息),采用专用的“安全屏幕”模式,具备:
- 额外遮罩。
- 禁止截屏/录屏支持。
- 避免在应用启动时自动读取剪贴板。
- 切勿将密码、令牌或重置链接写入剪贴板。
- 确保应用内截图或导出功能排除机密信息/PII,除非经过明确要求并清晰告知用户。
阶段 6:身份验证、授权与会话管理
认证流程
- 公开的 Flutter 客户端采用带有 PKCE 的 OAuth2/OIDC 认证。
- 切勿在客户端应用中嵌入 Client Secret。
- 优先使用系统浏览器/平台提供的安全认证流程:
- Android 上的 Chrome Custom Tabs。
- 通过插件调用 iOS 上的
SFSafariViewController/ASWebAuthenticationSession。 - 尽可能避免在内嵌 WebView 中执行登录。
令牌管理
- 使用短期有效的访问令牌。
- 仅将刷新令牌保存在与平台密钥库绑定的安全存储中。
- 定期轮换令牌。
- 在以下情况下使令牌失效:
- 登出。
- 设备变更。
- 出现可疑行为模式。
- 考虑针对高敏感度操作实施设备绑定和基于风险的检查,利用来自 Android 和 iOS 的设备环境信号。
授权控制
- 在服务端强制执行访问控制。
- 切勿依赖 Dart/UI 层逻辑来保护资源安全。
- 针对 Flutter 应用调用的所有 API 端点,测试以下漏洞:
- IDOR/BOLA。
- 批量分配。
- 垂直和水平越权提升。
阶段 7:WebView 加固与基于浏览器的流程
推荐模式
- 在可能的情况下,认证和支付流程优先使用系统浏览器/平台提供的安全 Web 视图:
- Custom Tabs。
-
SFSafariViewController。
若必须使用 WebView(Flutter WebView 或原生 WebView)
- 默认禁用 JavaScript。
- 仅在明确需要时启用 JavaScript,并严格限制其能力。
- 限制页面导航,仅允许访问受信主机和协议的白名单。
- 拦截并阻断
file://、javascript:等危险 URL。 - 在 Android 和 iOS 的发布版本中禁用 Web 内容调试功能。
- 在敏感会话(认证、支付、PII 编辑)结束后,清除 WebView 的 Cookie、缓存和本地存储。
- 确保第一方 Web 内容:
- 强制执行 CSP。
- 仅使用 HTTPS。
- 不存在混合内容。
阶段 8:应用间通信、深度链接与平台通道
深度链接与跨应用流转
- 深度链接优先采用 Android App Links 和 iOS Universal Links。
- 在执行操作前校验链接来源。
- 在执行操作前校验并净化链接参数。
- 避免使用不安全的自定义 URL Scheme。
- 若必须使用自定义 Scheme:
- 选用唯一的 Scheme 名称。
- 对所有参数和重定向进行严格校验。
平台通道(MethodChannel / EventChannel)
- 将所有从 Flutter 传入原生层以及反向传递的数据视为不可信数据,直至通过校验。
- 在原生端严格校验方法名和参数。
- 避免直接通过平台通道暴露高权限的原生 API。
- 切勿在未经验证和净化的前提下,将来自 Flutter 的原始不可信数据直接传递给特权原生调用(文件系统、系统设置、通信服务等)。
- 在测试期间对平台通道输入进行模糊测试。
- 记录并安全处理非预期的方法调用或畸形数据。
阶段 9:逆向工程与防篡改韧性
减少静态信息泄露
- 混淆 Dart 代码。
- 为 Android 启用 R8/ProGuard/资源缩减。
- 在双平台发布的二进制安装包中剥离符号和调试信息。
- 在发布版本中移除详细日志、调试菜单、测试端点、隐藏功能开关以及后门代码。
- 避免以易于提取的形式嵌入机密或敏感业务逻辑(例如静态资源中的明文字符串)。
运行环境检测
- 在 Android 和 iOS 双端添加 Root/越狱/Hook/调试器检测(通过插件或原生代码)。
- 记录检测到的风险信号以供安全监控。
- 采取合理的防御响应措施:
- 降级功能。
- 增加二次验证。
- 阻断高风险操作
而不是静默维持正常运行。
防篡改测试与完整性
- 验证通过完整性校验或服务端凭据认证能够检测到被重打包或重签名的 Flutter 应用:
- Play Integrity(Android)。
- iOS 设备健康检查。
- 将客户端防篡改检查作为上报至后端的信号指标。
- 绝不可将客户端防篡改检查作为唯一的安全控制手段。
阶段 10:密码学与随机数生成
- 使用成熟、经平台验证的加密库(例如封装 Android Keystore/iOS Keychain 的插件或经过充分安全审计的加密库)。
- 切勿在 Dart 中自行实现自定义加密算法。
- 加密方案应采用现代 AEAD 模式:
- AES-GCM。
- ChaCha20-Poly1305。
- 密钥派生函数(KDF)应选用:
- PBKDF2。
- HKDF
并配置合理的计算参数和每个值唯一的盐。 - 使用安全随机数生成器(SecureRandom 或通过插件调用平台 RNG)生成密钥、IV 和 Nonce。
- 切勿重复使用 IV/Nonce。
- 将加密密钥保存在受 Keystore/Keychain 保护的存储中或在静态存储时进行加密,不得在内存或配置中停留超过必要的时间。
阶段 11:权限、通知与设备标识符
权限管控
- 仅申请运行所必需的最小权限。
- 仅在实际使用功能的时刻动态申请权限。
- 提供清晰的用户体验,说明需要每项权限的原因。
- 实现友好的权限拒绝和撤销处理逻辑(提供降级功能,而非崩溃或无限弹窗)。
隐私与标识符
- 仅在符合平台策略的前提下使用广告/分析标识符(例如 GAID/IDFA),并配置完备的用户同意流。
- 避免使用以下信息构建跨应用的持久设备指纹:
- 硬件 ID。
- MAC 地址。
- 其他被禁用的标识符。
通知安全
- 尽可能减少推送/本地通知中的敏感内容。
- 锁屏通知使用通用、不包含具体信息的标题/描述。
- 允许用户配置通知类别及其敏感度。
- 切勿在通知负载中包含机密信息或完整 PII。
阶段 12:日志记录、遥测分析与崩溃报告
- 规范统一采用结构化日志记录。
- 在发布版本中禁用详细/调试日志。
- 从以下内容中脱敏 PII 和机密信息:
- 日志
- 遥测分析事件
- 崩溃报告
- 遥测分析优先采用数据聚合与采样机制。
- 在服务端安全存储符号/映射文件(Flutter 拆分调试信息、R8 映射文件、dSYM),以便对崩溃堆栈进行去混淆分析。
- 切勿在应用安装包中附带符号/映射文件。
- 定期审查遥测分析和日志,排查是否存在异常数据(敏感字段、查询参数、请求头、负载数据)。
阶段 13:测试、DAST 与运行时验证
流量拦截测试
- 验证 TLS 校验是否能够拒绝:
- 无效证书。
- 过期证书。
- 自签名证书(除非已明确信任)。
- 主机名不匹配。
- 确认已启用的证书绑定能够有效拦截 MITM 抓包工具。
运行时检查
- 在测试过程中,检查以下位置是否泄露机密/PII:
- 应用存储(
SharedPreferences、文件、数据库)。 - WebView 存储。
- 日志
- 确认安全存储和加密机制已正确生效。
- 确认注销登出/账号移除时的数据清理机制真实有效。
API 滥用测试
- 针对 Flutter 应用所调用的所有 API,验证:
- 速率限制。
- 防重放机制。
- 分页边界。
- 输入校验
- 检查服务端错误提示信息是否过于详细,避免泄露底层实现细节。
动态分析与 DAST
- 在覆盖 Flutter 核心业务流(认证、支付、个人资料、设置)的同时运行移动端 DAST 工具。
- 使用 DAST 发现并暴露:
- 传输层问题。
- 存储层问题。
- WebView 安全问题。
- 导出测试证据以供分级分类处理。
- 在正式发布版本晋级前修复所有安全发现并进行回归复测。
阶段 14:SBOM 与合规凭证
SBOM 与依赖项
- 生成并归档 SBOM:
- Flutter(
pubspec.lock)。 - 原生模块(Gradle/CocoaPods)。
- 持续追踪当前软件包依赖集的 CVE 漏洞和安全通告。
- 将依赖更新排入发布就绪流程的常规计划中。
凭证包
- 随每个发布归档记录附带:
- SAST/SCA/DAST 报告。
- SBOM。
- 构建配置(混淆、证书绑定、ATS/networkSecurityConfig)。
- 测试报告(自动化与人工测试)。
阶段 15:报告编制与标准合规映射
报告编制
- 为 Flutter 应用生成:
- 管理层摘要。
- 评估范围与方法学。
- 包含 PoC 和截图的详细漏洞发现。
- 风险评级。
- 整改修复计划。
- 复测结果。
OWASP MASVS 标准映射
- PLATFORM:阶段 2、7–8、11。
- STORAGE:阶段 3–4。
- CRYPTO:阶段 10。
- AUTH:阶段 6。
- NETWORK:阶段 5。
- CODE:阶段 2、8、12。
- RESILIENCE:阶段 9。
从业者快速参考
- 构建配置:
--obfuscate --split-debug-info,R8 开启minifyEnabled true、shrinkResources true;发布的产物中不含调试符号。 - 网络传输:全站 HTTPS;对关键 API 实施证书/SPKI 绑定(带备用 Pin);验证 MITM 拦截失败。
- 本地存储:令牌使用安全存储;敏感数据使用加密数据库/文件;登出时清空;禁止敏感数据明文备份。
- 身份认证:OIDC + PKCE;短期有效令牌;刷新令牌放入安全存储;服务端强制授权;测试 IDOR/BOLA 越权。
- WebView:认证优先采用系统浏览器;若使用 WebView,默认禁用 JS、设置导航白名单、敏感流程后清除数据。
- 隐私防护:通过平台标志在后台遮罩快照;避免将机密放入剪贴板;最小化权限并提供清晰的用户提示。
- CI 门禁:阻断高危/严重 SAST/SCA;要求 DAST 达到“零高危”;发布分支分析器与 lint 错误清零。