我的Android应用程序有一个excel导出和导入功能,我最近想通过添加写保护密钥来保护它。起初,我把密钥硬编码在源代码中,但显然由于逆向工程的原因,这根本不安全。我读了很多书,我认为我的解决方案现在是安全的,但我不确定。你能看看并指出可能的注意事项吗?
- 想要导出excel的用户必须使用谷歌登录的谷歌帐户登录
- 我的应用程序从谷歌请求登录令牌(通过sha签名验证)
- 登录令牌发送到我的服务器(HTTPS POST)
- 我的服务器验证该令牌是否是经过谷歌验证的有效令牌。文件:https://developers.google.com/identity/sign-in/android/backend-auth
- 以JSON格式(HTTPS POST)发回应用程序帐户信息和excel导出机密
- 应用程序使用密码保护excel表并将其导出
只有使用提供的密码导出的excel工作表才能再次导入。
我还有一个PDF导出功能。PDF应该由应用程序签名。该过程与以前相同,但使用了包含私钥和公钥的pkcs密钥作为base64字符串。
root设备如何?攻击者可能会获得发送的密码/pkcs密钥吗?
可能的洞穴
我读了很多书,我认为我的解决方案现在是安全的,但我不确定。你能看看并指出可能的注意事项吗?
乍一看:
- 从私钥离开后端服务器的那一刻起,它就属于公共域,因此必须将其视为已泄露
- 移动应用程序正在做出重要决策,对文档进行签名并验证其签名,而在运行时,使用Frida和xPosed等工具框架可以绕过这一点
- 后端服务器只对请求中的用户进行身份验证,而不是它发出请求的内容
1.私钥
- 以JSON格式(HTTPS POST)发回应用程序帐户信息和excel导出机密
过程与以前相同,但使用了一个pkcs密钥,该密钥包含作为base64字符串的私钥和公钥。
私钥保持私有的唯一方法是将其安全地存储在要使用的地方,我强烈建议在使用的同一个地方,也就是同一台服务器上生成它。
从私钥离开后端服务器的那一刻起,它就不再被安全存储,现在任何有技能和知识的人都可以使用大量开源和付费工具对静态二进制文件进行逆向工程,甚至在运行时对其进行内省,并更改其行为或提取数据,也就是您的公钥。
对于静态二进制分析,我们有一个开源工具MobSF,它结合了其他几个开源工具,可以对静态二进制进行反编译、分析和提取数据。
MobSF
移动安全框架(MobSF)是一个自动化的、一体化的移动应用程序(安卓/iOS/Windows)笔测试、恶意软件分析和安全评估框架,能够执行静态和动态分析。MobSF支持移动应用程序二进制文件(APK、IPA和APPX)以及压缩源代码,并提供RESTAPI,以便与CI/CD或DevSecOps管道无缝集成。动态分析器可帮助您执行运行时安全评估和交互式检测。
关于运行时,可以使用Frida或xPosed挂接到使用私钥的代码位置,并将其提取到攻击者服务器。
弗里达
将您自己的脚本注入黑盒进程。挂钩任何函数,监视加密API或跟踪私有应用程序代码,无需源代码。编辑,点击保存,立即查看结果。所有这些都没有编译步骤或程序重新启动。
xPosed
Xposed是一个框架,允许用户轻松地将附加组件(称为模块)应用到ROM。您可以使用Xposed将单个功能添加到您正在使用的任何ROM,甚至只是库存ROM,而不是闪烁一个新的ROM来获得特定功能。
2.应用内决策
- 应用程序使用密码保护excel表并将其导出
只有使用提供的密码导出的excel工作表才能再次导入。
正如我之前在这个答案中提到的,Frida和XPosed可以用于在运行时内省和插入代码。
攻击者可以使用其中一个工具挂接表明文档是否正确签名的函数,并始终返回true
,从而绕过移动应用程序代码中提供的所有预期安全机制。这是我之前提到的在运行时使用Frida或xPosed提取私钥的另一种方法。
3.访问后端服务器的人员与内容
- 想要导出excel的用户必须使用谷歌登录的谷歌帐户登录
- 我的应用程序从谷歌请求登录令牌(通过sha签名验证)
- 登录令牌发送到我的服务器(HTTPS POST)
- 我的服务器验证该令牌是否是经过谷歌验证的有效令牌。文件:https://developers.google.com/identity/sign-in/android/backend-auth
这4个步骤只识别请求中的Who,换句话说,请求是为用户发出的,但不提供任何形式的识别What代表用户发出请求。
为了获得更深入的解释,我建议你阅读我写的一篇文章,特别是其中的一节:你知道谁和什么在与你的Api服务器通信吗?:
是移动应用程序的用户,我们可以通过多种方式对其进行身份验证、授权和识别,例如使用OpenID Connect或OAUTH2流。
what是向API服务器发出请求的对象。它真的是你的移动应用程序的真实实例吗?还是机器人程序、自动脚本或攻击者用Postman这样的工具手动在你的API服务器上闲逛?
您可能会惊讶于攻击者是您试图绕过系统的真实用户的频率。
可能的解决方案
洞穴1
要解决警告1,您必须始终将私钥保存在后端服务器中,并且NEVER在对移动应用程序的任何响应中都不会发送私钥。
洞穴2
警告2可以通过不在移动应用程序中签名或验证文档来解决,而是在后端服务器中进行签名或验证,并且您必须确保后端服务器知道提出请求的Who和What。
洞穴3
警告3它已经部分解决了,一旦您已经知道请求中的Who,您只需要实现一个强大的解决方案来了解What它代表用户发出请求。
识别向后端服务器发出请求的最常见方法是在请求头中使用一个秘密,您可能知道该秘密为APi-Key
、Access-Token
或所选的任何其他名称,但您可以在文章《利用中间人攻击窃取Api密钥:》中看到这种方法是如何被中间人(MitM)攻击轻易绕过的
因此,在本文中,您将学习如何设置和运行MitM攻击,以拦截您控制的移动设备中的https流量,从而窃取API密钥。最后,您将从高层次了解如何减轻MitM攻击。
可以使用一个更强大的解决方案,其中另一个服务器可以证明移动应用程序的完整性,这将允许后端服务器知道何时信任是什么提出了请求,移动应用程序认证就知道这一概念。
移动应用程序认证服务的作用在我写的一篇文章中有更详细的解释,在"移动应用程序验证的作用:"一节中
移动应用验证服务的作用是验证发送请求的内容,从而仅响应来自真实移动应用实例的请求,并拒绝来自未经授权来源的所有其他请求。
为了了解向API服务器发送请求的内容,移动应用验证服务将在运行时高度自信地识别您的移动应用是否存在、未被篡改/重新打包、未在根设备中运行、未被仪器框架(Frida、xPosed、Cydia等)钩住,并且不是中间人攻击(MitM)的对象。这是通过在后台运行SDK来实现的,该SDK将与云中运行的服务进行通信,以证明其运行的移动应用程序和设备的完整性。
在成功证明移动应用程序完整性的基础上,将发布一个短时间生存的JWT令牌,并使用只有API服务器和云中的移动应用程序认证服务知道的秘密进行签名。在证明失败的情况下,JWT令牌将使用不正确的密钥进行签名。由于移动应用程序不知道移动应用程序验证服务使用的秘密,因此即使应用程序已被篡改、在根设备中运行或通过作为MitM攻击目标的连接进行通信,也不可能在运行时对其进行反向工程。
移动应用程序必须在每个API请求的头中发送JWT令牌。这允许API服务器仅在能够验证JWT令牌是使用共享密钥签名的并且尚未过期时才为请求提供服务。所有其他请求都将被拒绝。换句话说,有效的JWT令牌告诉API服务器,发出请求的是上传到谷歌或苹果商店的真实移动应用程序,而无效或丢失的JWT代币意味着发出请求的人没有被授权这样做,因为它可能是机器人程序、重新打包的应用程序或进行MitM攻击的攻击者。
虽然构建自己的移动应用程序验证服务并不容易,但由知识渊博的工程师团队来做是可行的,需要记住的主要一点是,SDK不执行任何决策,只是响应服务器给出的随机挑战,它是负责决定移动应用程序完整性的人。
结论
你目前的防御比最初的防御要好,你还有改进的空间,你应该在提高移动应用程序和后端服务器的安全性方面付出多少努力,可能需要与监管你正在做的事情、你和你的团队可用的知识库和资源的法律相平衡,并与你所保护的东西的价值成比例。
最后,我强烈建议您解决警告1和2,并尝试警告3。
多走一步
我一直想推荐这个非常有价值的资源OWASP移动安全测试指南
《移动安全测试指南》(MSTG)是一本关于移动应用程序安全开发、测试和逆向工程的综合手册。
首先,即使您将其编译为本机C文件,也没有100%安全的方法来存储它。
要隐藏它们,您可以在执行时对其进行加密和解密。要加密你的字符串并向丢失的黑客注入假代码,你可以尝试这个Gradle插件:https://github.com/christopherney/Enigma
我写了一篇关于它的短文:https://medium.com/@christophenney/protect-android-app-against-reverse-engineing-with-eigma-string-offstation-plugin-11687022cbef
还有其他插件,例如https://github.com/StringCare/AndroidLibrary