我正在开发与服务器通信的android应用程序,并且我想在运行时验证自发布以来我的应用程序没有被修改(具有修改后的应用程序的用户应无法登录到该应用程序)。
由于修改后的应用的签名不同于原始签名,所以我决定:
这是我上面1号的代码:
Context context = this;
PackageManager pm = context.getPackageManager();
String packageName = context.getPackageName();
int flags = PackageManager.GET_SIGNATURES;
PackageInfo packageInfo = null;
try {
packageInfo = pm.getPackageInfo(packageName, flags);
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
Signature[] signatures = packageInfo.signatures;
我的问题是:
(这也是我有史以来第一个关于stackoverflow的问题,因此非常感谢我提出这个问题时所犯的任何错误!。)
答案 0 :(得分:0)
首先,某人总是有可能绕过这种安全性,例如通过对传递给您服务器的证书进行硬编码。您只能尝试使其尽可能地困难,但绝对不会100%安全。
话虽这么说,您似乎在做。请注意,在最新的SDK中,不推荐使用pm.signatures
,而推荐使用pm.signingInfo
。
从大小上来说,证书并不大,但是要使请求更小,您可能应该只发送一个哈希(例如SHA256)。
为防止人们在请求中对证书进行硬编码,您还可以考虑将另一个值与证书一起哈希,即hash(certificate + timestamp),并在请求中还发送时间戳,以便您可以重新计算哈希服务器端。如果时间戳离当前日期太远,则拒绝该请求。同样,它也不是完全安全,而是增加了另一层复杂性来对代码进行反向工程。您还可以添加versionCode并开始拒绝旧版本的请求(例如,如果您在一个旧版本中检测到安全漏洞),并提示这些用户更新应用程序(或在后台为他们更新应用程序,仅提示输入安装,这要归功于新的API Play提供)。
正如某人指出的那样,您的代码还可以检查安装来自Play(packageManager.getInstallerPackageName(getPackageName()).equals("com.android.vending");
),但是该信息很容易被欺骗,因此不确定是否会增加很多安全性。
希望有帮助,
答案 1 :(得分:0)
正如@Pierre所指出的那样,您执行检查的方式是有效的,但是我想提醒您一个事实,即可以使用Frida或{ {3}},但仍然建议并鼓励将其用作另一个安全层。有关此方面的更多见解,请快速阅读xPosed,以了解如何轻松实现固定,从操作的角度来看,如何进行维护是一场噩梦,以及如何绕过它。
是否有更好的方法来验证apk?
是的,它存在,称为“移动应用证明”。该解决方案将包含一个集成在移动应用程序中的SDK,该SDK可在后台与云服务进行通信,因此不会影响用户体验。
移动应用程序认证解决方案在运行时保证应用程序不会受到中间人的攻击,被篡改,不在有根或越狱的设备中运行,未连接到调试器,不在模拟器上运行与上传到应用商店或Google Play商店中的原始照片相同。
因此,在成功证明移动应用程序完整性时,云服务会发布寿命很短的this article,该密钥使用仅由API服务器和云中运行的移动应用程序证明服务已知的秘密进行签名。在证明失败时,将使用API服务器未知的秘密对JWT进行签名。在向API服务器发送的每个请求中,移动应用都会发送此JWT令牌,并且API服务器将验证签名是否有效且令牌尚未过期,并且在验证失败时将拒绝该请求。
一旦移动应用程序不知道云证明服务使用的秘密,就不可能对JWT令牌进行反向工程,即使移动应用程序被篡改,在根设备上运行或通过连接进行通信是中间攻击中一个人的目标。
您可以在JWT token(我在这里工作)中找到这样的服务,其中包含适用于多个平台(包括Android)的SDK。集成还需要在API服务器代码中进行少量检查,以验证JWT令牌。
面向开发人员,逆向工程人员和安全研究人员的动态仪表工具包。
Xposed是一个模块框架,可以在不接触任何APK的情况下更改系统和应用程序的行为。
基于令牌的身份验证
JSON Web令牌是一种开放的行业标准RFC 7519方法,用于在双方之间安全地表示声明。