【技术深度】金融 / 钱包级 Android 安全性架构(毒APP)
作者:ZFJ_张福杰
博客:https://zfj1128.blog.csdn.net
日期:2025-12-17
关键词:Android、安全、签名证书
前言
今天我们交易所有个用户反馈自己的952.00U的资金被盗了,然后找到我们的客服,当然他资金被盗与我们交易所无关...
查询了他的账号登录记录,一直在他的安卓机上没有改变,不存在账号被盗的情况,然后我就在想,可能的原因:
- 用户手机被黑了,被远程控制了;
- 身边的人知道他的锁屏密码了,操作了他的手机(用户没有设置2fa,只有邮箱验证码);
- 用户自己转错币了(包括粘贴板被黑),来闹,想得到补偿;
- 下载的APP不是官方的APP,APP被藏毒了;
然后我想基于第四点【下载的APP不是官方的APP,APP被藏毒了;】,想来聊一聊如何去做攻防,这里不是官方APP又分为两点:
- 签名证书(keystore)泄露,得到了重新打包的APP;
- APP被反编译,重新签名了,不是原来的bid了;
需要说明的是, 一旦签名证书(keystore)泄露,Android 原生层面已经"无法 100% 阻止"被二次打包的 App 安装。
但可以做到的是:
- 让被篡改 / 非官方 App "无法正常使用核心功能"
- 在运行期"精准识别并封禁"非官方 App
- 让攻击成本远高于收益(工业级防护)
也就是说: 你阻止不了用户"安装",但你可以阻止它"活着"。
一、总体安全目标
1、钱包 / 金融 App 的核心安全目标:
不信任客户端,不信任系统,不信任安装来源。
2、整体架构鸟瞰:
Integrity Gateway 是金融 App 的"门神"。

二、签名泄露
1、为什么不能彻底阻止安卓?
Android 的签名机制本质,校验的是:
- APK 内的 签名是否自洽
- 不是校验「是不是你官方发的」
如果 攻击者拿到了你的签名证书:
- 他重新打包
- 用你的证书重新签名
- 系统层面 = 合法 App
Android 系统不会知道这是"假官方",签名证书也很容易泄露的,比如公司人员离职。
2、可行的防护思路(核心)
你的目标不是「阻止安装」,而是:
只允许"官方构建链 + 官方环境 + 官方完整性"的 App 运行
3、整体思路:

三、第一道防线:App 自身完整性校验(本地)
1、签名指纹校验(基础但必须)
防止最低级二次打包
在运行时校验:
- Signing Certificate SHA-256
- 对比硬编码的官方指纹
java
PackageInfo pkgInfo = getPackageManager()
.getPackageInfo(getPackageName(), PackageManager.GET_SIGNING_CERTIFICATES);
Signature[] signatures = pkgInfo.signingInfo.getApkContentsSigners();
MessageDigest md = MessageDigest.getInstance("SHA-256");
byte[] digest = md.digest(signatures[0].toByteArray());
⚠️ 注意 :
如果证书已经泄露,这一层 会被绕,但仍然是第一道门槛。
2、APK 文件完整性校验(Hash)
- 运行时计算 APK hash
- 对比 官方版本 hash 列表
text
官方版本 → server → 下发 hash 白名单
⚠️ 攻击者如果 修改代码后再签名,hash 一定变化。
3、Dex / SO 自校验(高级)
- 对关键 dex / so 做 hash
- 校验运行内存中的映射文件
常见校验点:
classes.dex- 核心 so(加壳后更佳)
4、运行环境检测
任何一个异常 → 风险标记
- Root 检测(最高优先级)
- Emulator 检测(反自动化)
- Frida / Xposed 检测(动态注入)
- Debuggable 检测(防调试)
- Hook Framework(通用框架)
四、第二道防线:Google 官方完整性证明(强烈推荐)
1、Play Integrity API(非常关键)
这是目前 唯一系统级可信方案。
2、它能告诉你:
- ✅是否来自 Google Play
- ✅是否是 官方签名
- ✅是否被 篡改 / 重打包
- ✅是否运行在 Root / Emulator
3、返回核心字段:
json
{
"appIntegrity": {
"appRecognitionVerdict": "PLAY_RECOGNIZED"
},
"deviceIntegrity": {
"deviceRecognitionVerdict": ["MEETS_DEVICE_INTEGRITY"]
}
}
4、你可以做什么?
- ❌ 非
PLAY_RECOGNIZED→ 直接禁用 - ❌ 被二次打包 → 拒绝登录 / 核心功能
相关策略:
| Verdict | 行为 |
|---|---|
| PLAY_RECOGNIZED + STRONG | 正常 |
| PLAY_RECOGNIZED + BASIC | 限额 |
| UNRECOGNIZED | 禁止核心功能 |
⚠️ 即便攻击者有你的证书:
Play Integrity 仍然能识别"非官方发布链"
五、第三道防线:服务端 Integrity Gateway裁决(最重要)
客户端永远只负责"提交证据",裁决权在服务器
1、启动即做远程认证
App 启动
↓
生成设备指纹 + 完整性报告
↓
服务器验证
↓
返回「是否允许使用」
校验维度:
| 项目 | 是否可信 |
|---|---|
| 签名指纹 | 中 |
| APK Hash | 高 |
| Play Integrity | 极高 |
| 设备指纹 | 中 |
| 行为特征 | 高 |
2、Token 绑定 App 完整性
-
登录 token = 绑定
- App 版本
- 签名
- Integrity 结果
篡改 App 即 token 失效。
六、第四道防线:身份 & Token 绑定(防重打包)
Token 不是"登录凭证",而是"设备+App 凭证"
Token 绑定:
- App Signature
- APK Hash
- Integrity Verdict
- Device Fingerprint
java
token = HMAC(user + app + device + integrity)
任一变化 → token 失效
七、终极方案(你问的"不是官方就禁止")
真正可落地的方案是:
只允许「Play Store 官方渠道 + Integrity 通过」的 App 使用
策略示例:
java
条件满足:
- Play Integrity = PASS
- APK hash ∈ 官方列表
- 服务端 token 校验通过
否则:
- 禁止登录
- 禁止交易
- 强制升级 / 提示风险
八、我想说
1、现实世界的边界
我们无法阻止安装非官方 App 使用,也无法绝对防破解,更做不到100% 本地可信,但是我们可以阻止非官方 App 使用,也可以识别重打包,再加上服务端封禁。
安全不是"是否被破解",而是"破解是否还有意义"。
2、一句话总结
Android 安全的本质不是防篡改,而是:"让任何非官方 App 即使能安装,也无法产生价值。"
关于作者(ZFJ_张福杰)
- 官网:https://zfjsafe.com
- 博客:https://zfj1128.blog.csdn.net
- Github:https://github.com/zfjsyqk
- Gitee:https://gitee.com/zfj1128
- 打赏:https://zfjsafe.com/paycode