本章把前四章整合成完整闭环:识别风险、验证风险、设计防护、实施改造、复测防护效果,最终输出可交付的安全评估报告。
1. 防护不是"加壳后结束"
安卓防护的目标不是让 App 永远不可逆向,而是提高攻击成本、减少客户端暴露、把关键判断放回可信边界,并建立持续复测机制。
| 层级 | 常见做法 | 价值 | 局限 |
|---|---|---|---|
| 代码混淆 | R8/ProGuard、资源混淆 | 降低静态阅读效率 | 不能保护硬编码秘密 |
| 完整性校验 | APK、DEX、so 哈希,签名摘要 | 发现重打包或篡改 | 客户端校验可被 Patch |
| 环境检测 | root、debug、proxy、Hook、模拟器检测 | 识别高风险环境 | 易误报,可被绕过 |
| 网络防护 | HTTPS、证书绑定、签名、重放防护 | 降低抓包和伪造请求风险 | 客户端密钥仍可能暴露 |
| 数据保护 | Keystore、加密存储、最小化缓存 | 降低本地数据泄露 | 运行时仍可被观察 |
| 服务端风控 | 鉴权、业务归属、订单状态、频控 | 最关键的安全边界 | 需要后端配合和监控 |
正确策略:客户端防护负责提高门槛和上报风险,服务端负责最终授权和业务一致性。
2. 风险分类与验证方法
2.1 客户端本地判断风险
知识点:
- 登录态、会员权益、支付状态、提现资格、优惠券使用资格不能只依赖客户端布尔值。
- 客户端变量、返回值、页面跳转都可被修改。
- 即使 UI 被保护,接口仍必须检查业务归属。
Demo 验证:
| 验证方式 | 工具 | 证据 |
|---|---|---|
Smali 修改 isVip() |
apktool + apksigner | 重打包后行为改变 |
Frida Hook isVip() |
Frida | Hook 日志和页面截图 |
| 接口直接访问会员资源 | Burp/mitmproxy | 服务端是否拒绝 |
修复:
- 会员状态由服务端返回并在关键接口再次校验。
- 客户端只做展示,不做最终授权。
- 服务端记录风险事件,例如客户端状态和服务端状态不一致。
2.2 硬编码密钥与签名算法风险
知识点:
- 客户端长期密钥会被静态搜索、动态打印或从内存中提取。
- 签名算法公开不是问题,密钥和服务端校验才是核心。
- 单纯 Base64、字符串拆分、简单异或不能算有效加密。
Demo 验证:
bash
jadx -d jadx-out app-release.apk
grep -R "demo-client-secret" -n jadx-out
Frida 打印签名前参数:
javascript
Java.perform(function () {
const Signer = Java.use("com.example.reversedemo.Signer");
Signer.sign.implementation = function (path, timestamp, nonce, body) {
console.log(path + "|" + timestamp + "|" + nonce + "|" + body);
return this.sign(path, timestamp, nonce, body);
};
});
修复:
- 避免在客户端保存长期共享密钥。
- 使用短期 token、服务端会话、设备绑定和服务端风控。
- 请求签名必须包含时间戳、nonce、body 摘要和服务端重放记录。
2.3 网络接口风险
验证项:
| 风险 | 测试方法 | 合格标准 |
|---|---|---|
| 越权访问 | 改 userId、订单 ID、资源 ID |
服务端按登录用户拒绝 |
| 重放请求 | 重发同一请求 | 服务端拒绝重复 nonce 或过期时间戳 |
| 参数篡改 | 修改金额、会员等级、权限字段 | 签名失败或业务拒绝 |
| 弱 token | 替换、删除、过期 token | 401/403 |
| 明文传输 | HTTP 或弱 TLS | 正式环境禁止 |
防护:
- 所有关键接口做身份认证和对象归属校验。
- 服务端保存 nonce 或请求摘要用于重放检测。
- 客户端证书绑定可提高抓包成本,但不能替代服务端校验。
2.4 本地数据风险
检查对象:
| 存储位置 | 风险 | 检查方式 |
|---|---|---|
| SharedPreferences | token、手机号、开关明文 | run-as、备份、root 环境查看 |
| SQLite/Room | 用户资料、缓存数据 | 导出 db,查看字段 |
| 外部存储 | 文件可被其他 App 或用户访问 | adb shell ls /sdcard/... |
| 剪贴板 | 验证码、token、密码残留 | 动态操作观察 |
| 日志 | 敏感字段输出 | adb logcat |
修复:
- 敏感数据最小化存储。
- 使用 Android Keystore 保护密钥材料。
- token 缩短有效期,支持服务端吊销。
- release 移除敏感日志。
3. 加固实践
3.1 R8/ProGuard 基础规则
build.gradle:
groovy
android {
buildTypes {
release {
minifyEnabled true
shrinkResources true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
}
示例规则:
proguard
-keep class com.example.reversedemo.api.ApiModel { *; }
-keepclassmembers class * {
native <methods>;
}
-assumenosideeffects class android.util.Log {
public static *** d(...);
public static *** v(...);
}
知识点:
-keep过多会削弱混淆效果。- Native 方法、反射、序列化模型需要谨慎保留。
- 混淆后必须跑自动化测试和逆向复测。
3.2 完整性和签名校验
Demo 签名摘要校验思路:
kotlin
fun currentSigningSha256(context: Context): String {
val packageInfo = context.packageManager.getPackageInfo(
context.packageName,
PackageManager.GET_SIGNING_CERTIFICATES
)
val cert = packageInfo.signingInfo.apkContentsSigners.first().toByteArray()
val digest = MessageDigest.getInstance("SHA-256").digest(cert)
return digest.joinToString(":") { "%02X".format(it) }
}
局限:
- 摘要常量如果放在客户端,也可能被定位修改。
- 校验函数本身可以被 Hook 或 Patch。
- 更好的做法是结合服务端挑战、设备完整性信号、行为风控和版本签名白名单。
3.3 证书绑定
OkHttp 示例:
kotlin
val pinner = CertificatePinner.Builder()
.add("api.example.com", "sha256/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=")
.build()
val client = OkHttpClient.Builder()
.certificatePinner(pinner)
.build()
知识点:
- 证书绑定能提高中间人抓包成本。
- 需要设计证书轮换策略,否则证书更新会导致客户端不可用。
- 绑定失败要记录错误,但不要泄露敏感实现细节。
3.4 环境检测
检测项可以包括:
| 检测 | 例子 | 处理建议 |
|---|---|---|
| root | su、Magisk 痕迹 |
作为风险信号,不直接一刀切 |
| 调试 | Debug.isDebuggerConnected()、TracerPid |
高风险操作二次校验 |
| 代理 | 系统代理、VPN、证书异常 | 对敏感接口加强风控 |
| Hook | Frida 线程、端口、maps | 记录风险,避免误伤 |
| 模拟器 | build 属性、硬件特征 | 结合业务场景判断 |
环境检测的关键是"分级响应":低风险提示,中风险限流,高风险要求二次认证或拒绝高危操作。
4. 复测方法
加固后必须用同样的攻击路径复测,而不是只看构建成功。
| 复测项 | 加固前结果 | 加固后期望 |
|---|---|---|
| jadx 阅读 | 类名、方法名清晰 | 关键类方法被混淆,敏感字符串减少 |
| Smali 修改 | 修改 isVip() 可生效 |
重打包被检测,服务端仍拒绝核心权益 |
| Frida Hook | Hook 返回值影响权益 | 客户端展示可变,但接口仍拒绝 |
| 抓包篡改 | 改参数可能成功 | 签名、鉴权、归属校验拒绝 |
| 重放请求 | 重发成功 | nonce 或时间戳拒绝 |
| Native 检测 | 可 Hook 单点绕过 | 绕过单点不影响服务端最终判断 |
复测结论要区分:
- 防护是否降低静态分析可读性。
- 防护是否能发现重打包或 Hook。
- 核心业务是否已迁移到服务端校验。
- 是否引入误报、崩溃、性能或兼容性问题。
5. 综合 Demo 项目
5.1 项目目标
围绕 ReverseDemo 完成一次完整安全闭环:
- 创建存在故意风险的 baseline 版本。
- 完成静态分析、动态分析、Native 分析。
- 验证本地会员判断、客户端签名、接口重放、Native 检测等风险。
- 实施防护改造。
- 复测并输出报告。
5.2 阶段计划
| 阶段 | 时间 | 任务 | 产出 |
|---|---|---|---|
| 1. Demo 准备 | 0.5 天 | 编译 debug/release,准备测试服务 | APK、接口说明 |
| 2. 静态分析 | 1 天 | Manifest、jadx、apktool、Smali 修改 | 静态报告 |
| 3. 动态分析 | 1 天 | logcat、抓包、Frida Hook | 动态报告 |
| 4. Native 分析 | 1 天 | so 提取、Ghidra、Native Hook | Native 报告 |
| 5. 防护改造 | 1 天 | 混淆、签名校验、服务端校验、重放防护 | 加固版本 |
| 6. 复测交付 | 0.5 天 | 按原攻击路径复测 | 总报告 |
5.3 最终目录
text
case-reversedemo/
01-env/
02-static/
03-dynamic/
04-native/
05-defense/
01-proguard-config.md
02-signature-check.md
03-server-validation.md
04-retest-matrix.md
05-final-report.md
6. 最终报告模板
markdown
# Android App 安全分析与防护复测报告
## 1. 测试边界
- App:
- 版本:
- 包名:
- 授权范围:
- 测试时间:
- 测试设备:
## 2. 工具版本
| 工具 | 版本 | 用途 |
## 3. 风险摘要
| 编号 | 风险 | 等级 | 验证方式 | 修复状态 |
## 4. 详细发现
### R-001 会员权益依赖客户端判断
- 证据:
- 复现步骤:
- 影响:
- 修复建议:
- 复测结果:
## 5. 防护改造
| 防护项 | 实施方式 | 覆盖风险 | 局限 |
## 6. 复测矩阵
| 攻击路径 | 加固前 | 加固后 | 结论 |
## 7. 剩余风险
-
## 8. 结论
7. 能力验收清单
| 能力 | 初级合格 | 进阶合格 | 专家方向 |
|---|---|---|---|
| APK 结构 | 能解释每个目录 | 能从结构判断分析重点 | 能制定自动化信息提取脚本 |
| Manifest 分析 | 能找导出组件 | 能验证组件风险 | 能形成安全基线 |
| jadx 分析 | 能定位关键方法 | 能还原调用链 | 能处理混淆、反射、动态加载 |
| Smali 修改 | 能修改返回值 | 能保持 APK 可运行 | 能理解寄存器和控制流影响 |
| 抓包 | 能抓 Demo 请求 | 能做篡改和重放测试 | 能设计接口安全测试矩阵 |
| Frida Hook | 能 Hook Java 方法 | 能打印签名前参数 | 能处理 ClassLoader、Native、反检测 |
| Native 分析 | 能找到 JNI | 能用 Ghidra 解释检测逻辑 | 能结合动态 Hook 还原算法 |
| 防护复测 | 能启用混淆 | 能按原路径复测 | 能建立版本化安全验收流程 |
8. 常见误区
| 误区 | 为什么错 | 正确做法 |
|---|---|---|
| "加壳后就安全" | 运行时仍可观察和 Hook | 多层防护加服务端校验 |
| "HTTPS 就不能抓包" | 用户证书、调试配置、错误信任链会暴露 | release 严格网络配置和证书绑定 |
| "root 检测能阻止攻击" | 检测可被绕过且可能误伤 | 风险评分和关键操作二次校验 |
| "混淆能保护密钥" | 密钥运行时必须出现 | 避免客户端长期密钥 |
| "客户端签名能防伪造" | 算法和密钥都在客户端时可被复现 | 服务端掌握核心秘密并做重放防护 |
| "Hook 成功就等于漏洞" | 还要看服务端是否受影响 | 用接口结果证明业务影响 |
9. 本章交付物
text
case-reversedemo/
05-defense/
01-risk-summary.md
02-defense-plan.md
03-implementation-notes.md
04-retest-matrix.md
05-final-report.md
最终验收标准:
- 五类证据齐全:命令输出、截图、反编译定位、Hook 日志、接口请求响应。
- 每个风险都有复现步骤和修复建议。
- 每个修复都有复测结果。
- 明确哪些风险已修复,哪些只是提高了攻击成本,哪些仍依赖服务端或业务改造。
10. 安全基线
10.1 Android 客户端安全基线
| 类别 | 基线项 | 最低要求 | 验证 |
|---|---|---|---|
| 构建 | release 关闭 debuggable | debuggable=false |
Manifest 和 dumpsys |
| 构建 | 启用 R8 混淆 | 类名方法名混淆 | jadx 对比 |
| 日志 | release 无敏感日志 | token、密码、签名明文不输出 | logcat |
| 网络 | 正式环境 HTTPS | 禁止明文 HTTP | 抓包和配置 |
| 网络 | 关键域名证书绑定 | 高风险接口启用 | MITM 复测 |
| 鉴权 | 服务端最终授权 | 不信任客户端 userId | Burp 篡改 |
| 重放 | nonce 和时间戳 | 重放旧请求被拒绝 | Repeater |
| 存储 | token 最小化保存 | 不明文长期保存 | 文件检查 |
| 组件 | 非必要组件不导出 | exported=false | Manifest |
| WebView | JSBridge 最小暴露 | 域名和参数校验 | 静态和动态 |
| Native | 检测只作为信号 | 不单点阻断核心业务 | Hook 复测 |
| 完整性 | 识别重打包 | 签名和版本校验 | 重签名安装 |
10.2 风险分级
| 等级 | 判断标准 | 示例 | 处理时限 |
|---|---|---|---|
| 高 | 可直接造成越权、资金、账号或敏感数据风险 | 服务端信任客户端会员状态 | 立即修复 |
| 中 | 提高攻击成功率或泄露关键线索 | 硬编码签名密钥、敏感日志 | 近期修复 |
| 低 | 信息暴露或防护不足但暂无直接业务影响 | 类名未混淆、普通调试文案 | 版本迭代修复 |
| 观察 | 需要更多证据确认 | 可疑导出组件但未触发敏感动作 | 补充验证 |
11. 防护设计详解
11.1 混淆策略
混淆的价值是提高静态阅读成本,不是保护核心秘密。
| 策略 | 作用 | 注意 |
|---|---|---|
| 类名方法名混淆 | 降低 jadx 可读性 | 反射、序列化需 keep |
| 资源压缩 | 移除未用资源 | 防止误删动态资源 |
| 日志移除 | 减少敏感输出 | 保留必要崩溃上报 |
| 字符串处理 | 降低直接搜索命中 | 运行时仍可被观察 |
| 控制流混淆 | 提高反编译难度 | 可能影响性能和稳定性 |
混淆复测:
bash
./gradlew assembleRelease
jadx -d release-jadx app-release.apk
grep -R "demo-client-secret" -n release-jadx
grep -R "UserCenter" -n release-jadx
11.2 服务端化授权
错误设计:
text
客户端判断 isVip=true -> 打开会员资源
正确设计:
text
客户端请求会员资源 -> 服务端根据 token 查询账号权益 -> 服务端返回资源或拒绝
接口要求:
| 要求 | 说明 |
|---|---|
| token 绑定用户 | 不信任客户端传入 userId |
| 资源归属校验 | 订单、文件、会员资源必须属于当前用户 |
| 状态实时校验 | 支付、退款、过期要实时或准实时 |
| 风险信号参与 | root、hook、代理只作为风控输入 |
| 审计日志 | 记录异常访问和签名失败 |
11.3 请求签名设计
推荐签名材料:
text
method + "\n" +
path + "\n" +
timestamp + "\n" +
nonce + "\n" +
sha256(body) + "\n" +
sessionScopedSecret
服务端必须检查:
- timestamp 是否在有效窗口。
- nonce 是否首次出现。
- body hash 是否匹配。
- token 是否有效。
- path 和 method 是否参与签名。
- 风险设备是否需要二次验证。
客户端不应持有全局长期密钥。可以使用登录后下发的短期会话材料,并配合服务端吊销。
12. 完整性和重打包防护
12.1 检测项
| 检测 | 方法 | 局限 |
|---|---|---|
| 签名摘要 | 读取 APK 签名证书 | 客户端常量可 Patch |
| DEX hash | 读取 classes.dex 哈希 |
计算函数可 Hook |
| so hash | 读取自身 so | 可替换校验结果 |
| installer | 检查安装来源 | 可伪造或不可靠 |
| versionCode | 检查版本 | 只防低级篡改 |
12.2 复测路径
- 修改 Smali。
- 重打包签名。
- 安装运行。
- 观察是否检测到重签名。
- 即使客户端未检测,访问关键接口。
- 服务端检查签名白名单或设备风险。
- 输出复测结论。
结论分级:
| 结果 | 说明 |
|---|---|
| 客户端阻断 | 能发现重打包,但仍需防 Hook |
| 服务端拒绝 | 核心业务安全边界有效 |
| 只提示风险 | 用户体验较好,但要限制高危操作 |
| 无任何变化 | 防护缺失 |
13. 证书绑定和网络复测
13.1 证书绑定上线清单
| 项目 | 要求 |
|---|---|
| 绑定对象 | 绑定公钥 pin 优先于叶子证书 |
| 备用 pin | 至少准备一个备用证书或公钥 |
| 轮换策略 | 证书过期前可平滑切换 |
| 灰度 | 分批开启,监控失败率 |
| 失败处理 | 不泄露内部细节 |
| debug 分离 | debug 可抓包,release 严格 |
13.2 网络防护复测
| 测试 | 加固前 | 加固后预期 |
|---|---|---|
| 用户 CA 抓包 | 可看到明文 | release 阻断 |
| 参数篡改 | 可能成功 | 签名失败 |
| 重放 | 可能成功 | nonce 拒绝 |
| 删除 token | 可能返回异常数据 | 401/403 |
| 改 userId | 可能越权 | 403 |
14. 本地数据防护
14.1 数据分类
| 数据 | 是否可本地保存 | 建议 |
|---|---|---|
| 用户名 | 可有限保存 | 避免敏感组合 |
| 密码 | 不保存 | 使用 token |
| token | 尽量短期 | Keystore 辅助保护 |
| refresh token | 谨慎 | 服务端可吊销 |
| 身份证/银行卡 | 不建议 | 服务端保存 |
| 会员状态 | 可缓存展示 | 关键接口服务端校验 |
| 风险结果 | 可缓存短期 | 不作为唯一依据 |
14.2 Keystore 使用边界
Keystore 可以提高密钥提取难度,但不能阻止运行时 Hook 明文输入输出。
验证方式:
- 静态检查是否有硬编码密钥。
- 动态 Hook 加密前后的数据。
- 检查密钥是否可导出。
- 检查 token 有效期和吊销机制。
15. 综合复测矩阵
| 编号 | 攻击路径 | 目标风险 | 加固前证据 | 加固后复测 | 结论 |
|---|---|---|---|---|---|
| R-001 | jadx 搜索密钥 | 硬编码秘密 | 命中 secret | 未命中或仅短期材料 | 记录 |
| R-002 | Smali 改会员 | 本地判断 | 非会员进入页面 | 接口拒绝 | 记录 |
| R-003 | Frida Hook 会员 | 运行时篡改 | 页面变化 | 核心资源拒绝 | 记录 |
| R-004 | 抓包改 userId | 越权 | 返回他人数据 | 403 | 记录 |
| R-005 | 重放请求 | 重放 | 重放成功 | nonce 拒绝 | 记录 |
| R-006 | 用户 CA 抓包 | MITM | 明文可见 | release 阻断 | 记录 |
| R-007 | 重签名安装 | 篡改 | 安装可运行 | 风险识别或服务端拒绝 | 记录 |
| R-008 | Hook root 检测 | 单点检测 | 返回值可改 | 只影响风险信号 | 记录 |
| R-009 | 查看本地存储 | 数据泄露 | token 明文 | 无长期敏感数据 | 记录 |
| R-010 | 导出页面启动 | 组件暴露 | 可直接打开 | 关闭或鉴权 | 记录 |
16. CI 安全检查
可以把部分检查放入 CI:
| 检查 | 示例 |
|---|---|
| release 不可 debuggable | 解包 Manifest 检查 |
| 禁止明文 HTTP | 检查 network config |
| 禁止敏感日志关键词 | 扫描 Log. 和关键词 |
| 禁止硬编码密钥 | 扫描 secret、key、token |
| 混淆开启 | 检查 release 配置 |
| 依赖漏洞 | Gradle dependency check |
示例伪脚本:
bash
apktool d -f app-release.apk -o ci-decoded
grep -R "android:debuggable=\"true\"" ci-decoded/AndroidManifest.xml && exit 1
grep -R "usesCleartextTraffic=\"true\"" ci-decoded/AndroidManifest.xml && exit 1
CI 只能做基线,不替代人工逆向复测。
17. 最终交付包
text
android-security-delivery/
00-scope/
authorization.md
app-info.md
01-static/
manifest-audit.md
jadx-code-map.md
smali-patch-proof.md
02-dynamic/
logcat-evidence.txt
http-repeater-tests.md
frida-hook-logs.md
03-native/
so-info.md
ghidra-notes.md
native-hook-proof.md
04-defense/
defense-plan.md
implementation-notes.md
retest-matrix.md
05-report/
final-report.md
executive-summary.md
17.1 高层摘要模板
markdown
# Executive Summary
本次测试覆盖 Android App 的静态逆向、动态抓包、Frida Hook、Native 分析和防护复测。
共发现高风险 X 项、中风险 X 项、低风险 X 项。
已验证核心问题包括:
1.
2.
3.
整体结论:
- 客户端防护:
- 服务端校验:
- 剩余风险:
- 下一版本建议:
17.2 技术报告验收标准
| 项目 | 要求 |
|---|---|
| 可复现 | 每个风险有命令、脚本或截图 |
| 可验证 | 每个修复有复测结果 |
| 可落地 | 建议能分配给客户端或服务端执行 |
| 有边界 | 写清授权范围和未覆盖范围 |
| 不夸大 | 区分"可 Hook UI"和"业务可越权" |
18. 学习路线升级
| 阶段 | 目标 | 产出 |
|---|---|---|
| 第 1 周 | 环境和 Demo | Demo APK、环境记录 |
| 第 2 周 | 静态分析 | Manifest 和 jadx 报告 |
| 第 3 周 | Smali 重打包 | Patch 证据 |
| 第 4 周 | 抓包和接口 | 接口风险矩阵 |
| 第 5 周 | Frida Java Hook | Hook 脚本库 |
| 第 6 周 | Native 入门 | JNI 映射报告 |
| 第 7 周 | 防护改造 | 加固版本 |
| 第 8 周 | 复测交付 | 完整报告 |
19. 专家级思考题
- 如果客户端
isVip()被 Hook,但服务端仍拒绝会员资源,这是否算高风险?为什么? - 证书绑定会导致无法抓包,是否说明接口安全?还需要验证什么?
- 签名算法在客户端实现是否一定不安全?核心判断标准是什么?
- Native root 检测被绕过后,如何设计服务端风控响应?
- 如何区分"混淆提高分析成本"和"真正修复风险"?
- 为什么重打包检测不能替代服务端鉴权?
- 哪些数据可以缓存到本地,哪些必须服务端实时查询?
- 如何把逆向复测纳入每个版本发布流程?
20. 防护、复测与交付
防护章节的知识点要区分提高攻击成本、发现风险信号和真正修复业务漏洞。最终以复测证据关闭风险。
防护策略
| 知识点 | 核心理解 | Demo/验证 | 常见误区 |
|---|---|---|---|
| 分层防护 | 客户端提高成本,服务端承担最终授权。 | Hook 客户端后服务端仍拒绝资源。 | 把加固当作业务修复。 |
| R8 混淆 | 降低静态阅读效率,不能保护运行时明文。 | jadx 对比 release 类名。 | 混淆后就不做服务端校验。 |
| 日志清理 | release 不应输出 token、密码、签名前明文。 | 运行关键流程检查 logcat。 | 只清自己日志,不查第三方库。 |
| 完整性校验 | 识别重打包、DEX 修改和 so 替换。 | 重签名包访问关键接口。 | 客户端校验可 Patch,不能单独依赖。 |
| 环境检测 | root、Hook、代理、模拟器作为风险信号。 | Hook 检测返回值后复测接口。 | 一刀切封禁导致误伤。 |
| 证书绑定 | 降低 MITM 抓包和篡改成本。 | release 用户 CA 抓包失败。 | pinning 替代服务端鉴权。 |
服务端安全
| 知识点 | 核心理解 | Demo/验证 | 常见误区 |
|---|---|---|---|
| 最终授权 | 会员、支付、订单、提现必须服务端判断。 | 客户端 isVip=true 后访问 /vip/resource。 |
服务端信任客户端状态。 |
| 资源归属 | 对象 ID 必须属于当前 token 用户。 | 改 userId、orderId、fileId。 | 只验证登录,不验证归属。 |
| 请求签名 | 签名覆盖 method、path、timestamp、nonce、body hash。 | 篡改 body 不改签名。 | 签名只覆盖部分字段。 |
| nonce 防重放 | nonce 必须服务端保存并一次性使用。 | 重复发送同一请求。 | 客户端生成但服务端不校验。 |
| token 吊销 | 泄露或退出后 token 应可失效。 | 退出后重放旧 token。 | 只依赖客户端删除 token。 |
| 风险风控 | 环境检测结果应进入服务端风险评分。 | 上报 root/hook/proxy 风险信号。 | 客户端自己决定是否允许交易。 |
复测交付
| 知识点 | 核心理解 | Demo/验证 | 常见误区 |
|---|---|---|---|
| 按原路径复测 | 修复后用同样 Smali、Frida、抓包路径验证。 | 复测 isVip Hook 和接口访问。 |
只看代码改动,不跑攻击路径。 |
| 风险关闭标准 | 必须有修复说明、复测结果和剩余风险。 | 更新复测矩阵。 | 开发口头说明即关闭风险。 |
| 高层摘要 | 给管理者说明影响、范围、状态和下一步。 | 输出 executive-summary.md。 |
堆技术细节没有业务结论。 |
| 技术报告 | 给开发可复现步骤、证据和修复建议。 | 输出 final-report.md。 |
无类名、接口、命令,无法修复。 |
| CI 门禁 | 自动检查 debuggable、明文流量、敏感关键词和混淆。 | 构建后解包扫描。 | 用 CI 代替人工复测。 |
| 剩余风险 | 有些防护只能提高成本,必须如实写明。 | 区分已修复、已缓解、待后端改造。 | 为了好看把缓解写成修复。 |