42 · 移动应用安全与加固
一句话定位:移动安全不是"加个混淆"就完事,而是一条纵深链:传输层(SSL Pinning)→ 存储层(安全存储)→ 代码层(混淆加固)→ 运行时(反调试)。对应前端的 08 · 前端安全,但移动端多了"逆向"这个威胁面。
开篇速览
| 问题 | 答案 |
|---|---|
| 前端对应物 | HTTPS/证书、XSS/CSRF、代码混淆、防调试 |
| 移动端独有威胁 | APK/IPA 可被解包逆向、证书中间人、root/越狱环境 |
| 最常被忽略 | 密钥/密钥字符串硬编码在 Dart 里,混淆挡不住 |
| 一句话红线 | "混淆"是降低逆向成本的手段,不是安全边界;真正的密钥必须进原生安全存储,不进 Dart 源码 |
代码来源说明:HaierEnergy 使用 Dio 请求(见 09 篇),有证书配置痕迹;是否做 SSL Pinning 需按发布环境确认。 本篇给出通用纵深方案。
一、纵深防御四层
传输层 SSL Pinning / 证书校验
↓
存储层 flutter_secure_storage / Keystore / Keychain
↓
代码层 混淆 + 资源裁剪(Android R8 / iOS 发布)
↓
运行时 root/越狱检测、反调试、防抓包二、传输层:SSL Pinning
防止中间人抓包篡改。Dio 侧可在拦截器做证书校验:
dart
// 伪代码:Dio 证书校验(真实实现要把 CA/公钥放到 assets 或原生层)
final dio = Dio(BaseOptions(baseUrl: baseUrl));
// 校验服务端证书是否匹配固定公钥实现层选择:
| 方案 | 位置 | 优点 | 注意 |
|---|---|---|---|
| 原生层证书锁定 | Android/iOS 原生 | 最可靠,抓包也难绕过 | 证书轮换要发版 |
| Dio 拦截器校验 | Dart 层 | 灵活、跨端统一 | 反编译可绕过,仅防"普通中间人" |
| 混合(原生 + Dart 兜底) | 双端 | 纵深 | 维护成本高 |
经验:证书/公钥要有轮换机制(备份公钥 + 版本控制),否则证书过期就是线上事故。
三、存储层:密钥与敏感数据
不要用 SharedPreferences 存密钥/token:
| 数据 | 正确存储 | 原因 |
|---|---|---|
| 用户 token | flutter_secure_storage(Keychain/Keystore) | 加密 + 系统级保护 |
| API 密钥 | 原生层(Android BuildConfig/原生 Secret) | 不进 Dart 源码 |
| 用户配置 | SharedPreferences | 非敏感,可明文 |
| 设备标识 | 匿名化 ID,不落敏感关联 | 隐私合规(见 38 篇) |
dart
// 敏感 token 走安全存储
const storage = FlutterSecureStorage();
await storage.write(key: 'access_token', value: token);四、代码层:混淆与加固
4.1 Android
- 发布构建开
minifyEnabled(R8 混淆 + 裁剪); - 商业加固(如腾讯乐固/梆梆/爱加密)做二次加固;
- 资源裁剪降低逆向面与体积。
4.2 iOS
- 发布构建默认 LLVM 优化,App Store 做基本保护;
- 商业加固可选(越狱检测等)。
注意:混淆会让崩溃堆栈难读,需配合 20 篇 的符号化还原流程。
五、运行时:root/越狱与反调试
高价值业务(支付、企业凭据)才需要:
- root/越狱检测:
root_detector等插件,检测到后提示并降级/拒绝敏感操作; - 防调试/防抓包:
Debug.isDebugMode检查 + 发布版关闭日志; - 注意:检测逻辑写在 Dart 里可被逆向定位,关键判定尽量下沉原生。
六、WebView 与 Deep Link 安全
(与 24 篇 联动)
| 风险 | 措施 |
|---|---|
| WebView 打开不可信 URL | 白名单校验,禁止任意 file:// / javascript: |
| Deep Link 被伪造拉起 | 校验 scheme/host + 参数签名 |
| JS Bridge 任意调用 | 只暴露白名单方法,校验来源 |
七、安全基线清单(项目落地)
- 必须:token 进安全存储、API 密钥不进 Dart、HTTPS + 证书校验;
- 建议:SSL Pinning(含轮换机制)、Android 混淆 + 加固、崩溃符号化;
- 按业务:root/越狱检测、反调试、WebView 白名单;
- 流程:上线前做一次渗透/逆向评估,安全测试进 CI。
动手练习
- 用
flutter_secure_storage重构"token 明文存 SharedPreferences"的旧逻辑; - 给 Dio 加证书校验拦截器(含备份公钥轮换的注释);
- 画一张"App 安全纵深"清单,标出每条措施落在哪一层。
自检清单
- [ ] 能说出四层安全纵深(传输/存储/代码/运行时)
- [ ] 知道 SSL Pinning 的实现位置与证书轮换
- [ ] 知道密钥为什么不能进 Dart 源码
- [ ] 知道混淆不是安全边界,只是加高逆向成本
- [ ] 会处理 WebView / Deep Link 的常见风险
常见误区
- "混淆了就很安全":混淆可被还原,密钥放 Dart 照样被抠出来;
- "token 存 SharedPreferences 方便":明文存储是重灾区,改安全存储;
- "SSL Pinning 一劳永逸":证书会过期,没有轮换机制就是定时炸弹;
- "检测写 Dart 就行":关键安全判定要下沉原生,Dart 层可被逆向定位。
相关文档
- 00 · 学习路线图 —— 阅读顺序
- 08 · 前端安全 —— 前后端安全对照
- 09 · 数据层链路 —— Dio 与请求层
- 18 · 本地存储与持久化 —— 与安全存储的分工
- 20 · 异常捕获与错误监控 —— 混淆后的符号化
- 24 · 推送通知与深链接 —— Deep Link 校验