风险模型
| 环节 | 风险 |
|---|---|
| 本地存储 | 明文存储 Token、数据库泄漏 |
| 网络传输 | 中间人攻击、证书伪造 |
| 代码与逻辑 | 逆向分析、调试注入 |
| 第三方 SDK | 数据滥用、隐私泄露 |
本地数据保护
- 使用
EncryptedSharedPreferences。 - Room 加密:
SQLCipher或WCDB。 - 文件加密:AES + 文件分块。
val masterKey = MasterKey.Builder(context)
.setKeyScheme(MasterKey.KeyScheme.AES256_GCM)
.build()
val securePrefs = EncryptedSharedPreferences.create(
context,
"secure_settings",
masterKey,
EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
)
网络安全
- 强制 HTTPS,禁用明文流量。
- 证书钉扎:OkHttp
CertificatePinner。 - 请求签名:HMAC + 时间戳。
val certificatePinner = CertificatePinner.Builder()
.add("api.example.com", "sha256/AAAAAAAAAAAAAAAAAAAA=")
.build()
val client = OkHttpClient.Builder()
.certificatePinner(certificatePinner)
.build()
代码防护
- R8 混淆、去除日志。
- 启用
minifyEnabled+shrinkResources。 - 使用
BuildConfig.DEBUG控制调试开关。
proguard-rules.pro
-keep class kotlinx.coroutines.** { *; }
-keepclassmembers class * implements android.os.Parcelable {
public static final android.os.Parcelable$Creator *;
}
-assumenosideeffects class android.util.Log {
public static *** d(...);
}
设备完整性检测
- Root/越狱检测:
SafetyNet、Play Integrity。 - Debug 检测:
adb、isDebuggerConnected()。
if (Debug.isDebuggerConnected()) {
throw SecurityException("Debugger detected")
}
权限最小化
- 清单中仅声明必要权限。
- 动态权限申请前提醒用户用途。
- 对敏感权限设置降级方案。
日志与监控
- 日志脱敏:对手机号、身份证号等做掩码。
- 安全告警:接入 SIEM 或自建审计。
- 数据生命周期:按需设置自动清理策略。
安全测试
- 静态扫描:
MobSF、SonarQube。 - 动态测试:抓包、注入测试。
- 模糊测试:对 API 接口进行异常输入测试。
./gradlew assembleRelease \
-Pandroid.injected.signing.store.file=keystore.jks \
-Pandroid.injected.signing.store.password=***
常见问题
| 问题 | 原因 | 解决方案 |
|---|---|---|
| 混淆导致崩溃 | keep 规则缺失 | 根据堆栈补充 keep,关注反射与序列化框架 |
| 证书钉扎失败 | 证书更新后 hash 不匹配 | 在服务端更新新证书时同时发布新 hash |
| 安全补丁滞后 | 依赖库过旧 | 定期检查 CVE,建立依赖升级流程 |
实战案例:Android 的安全是”纵深防御”,没有银弹
我在 Flutter 货运项目(某物流冷链项目)里,有司机身份证认证(image_picker 拍证件照)+ token 存 SharedPreferences 明文——这就是典型的”知道但没做到”。Android 原生的标准答案比 Flutter 更完整:
- 存:
EncryptedSharedPreferences(AndroidX Security)或 DataStore + Tink,密钥进 Keystore(最好 StrongBox 硬件级)。Flutter 侧对等的是flutter_secure_storage。 - 传:
network_security_config.xml强制 HTTPS + 证书钉扎(CertificatePinner)。Flutter 侧是dio的certificatePinner或原生层配置。 - 防逆向:R8 混淆是基线,
App Integrity/ Play Integrity API 防改包。Flutter 的--obfuscate对等,但 Dart 的字符串常量在二进制里是明文——敏感 key 别放 Dart 层。 - 防调试/Root:
SafetyNet/Play Integrityverdict,root 检测用 RootBeer 这类库。注意:检测只能提高门槛,不能杜绝,别在客户端做最终的安全决策。
最扎心的一条:客户端没有秘密。任何放进 App 的密钥、算法,熟练的逆向者都能拿出来。真正的敏感逻辑放服务端,客户端只做”增加攻击成本”。这个认知比任何具体技术都重要。
参考:Android 官方文档《App security best practices》;OWASP MASVS
总结
- Kotlin 提供多种安全工具,需要结合系统能力与第三方方案整体设计。
- 建立“存储、传输、代码”三位一体的安全策略。
- 将安全测试与监控纳入 CI/CD,实现持续的风险发现与响应。
