您的问题
在 Android 应用中安全保存静态信息的位置?
无论您将它们存储在何处以及如何存储,因为从您发布移动应用的那一刻起,其上的任何秘密现在都属于公共领域。
我也尝试过 Cryptography,但我还必须存储 secretKey 以进行解密。
您可以通过将其隐藏在 C 代码中,使用 Android 中的 JNI/NDK 接口来使其难以通过静态分析进行逆向工程,就像我在这个 Currency Converter Demo 存储库中所做的那样,但是如果攻击者无法要以这种方式对其进行逆向工程,他将在运行时使用检测框架进行此操作,流行的一种是Frida:
将您自己的脚本注入黑盒进程。挂钩任何功能、监视加密 API 或跟踪私有应用程序代码,无需源代码。编辑,点击保存,立即查看结果。所有这些都无需编译步骤或程序重新启动。
另一种选择是尝试在运行时计算密钥,但随后 Frida 将再次挂钩执行此操作的函数并从其返回值中提取密钥。
在运行时计算 HMAC 的基本代码示例可以在ShipFast Demo repo 中找到:
private fun calculateAPIRequestHMAC(url: URL, authHeaderValue: String): String {
val secret = JniEnv().getHmacSecret()
var keySpec: SecretKeySpec
// Configure the request HMAC based on the demo stage
when (currentDemoStage) {
DemoStage.API_KEY_PROTECTION, DemoStage.APPROOV_APP_AUTH_PROTECTION -> {
throw IllegalStateException("calculateAPIRequestHMAC() not used in this demo stage")
}
DemoStage.HMAC_STATIC_SECRET_PROTECTION -> {
// Just use the static secret to initialise the key spec for this demo stage
keySpec = SecretKeySpec(Base64.decode(secret, Base64.DEFAULT), "HmacSHA256")
Log.i(TAG, "CALCULATE STATIC HMAC")
}
DemoStage.HMAC_DYNAMIC_SECRET_PROTECTION -> {
Log.i(TAG, "CALCULATE DYNAMIC HMAC")
// Obfuscate the static secret to produce a dynamic secret to initialise the key
// spec for this demo stage
val obfuscatedSecretData = Base64.decode(secret, Base64.DEFAULT)
val shipFastAPIKeyData = loadShipFastAPIKey().toByteArray(Charsets.UTF_8)
for (i in 0 until minOf(obfuscatedSecretData.size, shipFastAPIKeyData.size)) {
obfuscatedSecretData[i] = (obfuscatedSecretData[i].toInt() xor shipFastAPIKeyData[i].toInt()).toByte()
}
val obfuscatedSecret = Base64.encode(obfuscatedSecretData, Base64.DEFAULT)
keySpec = SecretKeySpec(Base64.decode(obfuscatedSecret, Base64.DEFAULT), "HmacSHA256")
}
}
Log.i(TAG, "protocol: ${url.protocol}")
Log.i(TAG, "host: ${url.host}")
Log.i(TAG, "path: ${url.path}")
Log.i(TAG, "Authentication: $authHeaderValue")
// Compute the request HMAC using the HMAC SHA-256 algorithm
val hmac = Mac.getInstance("HmacSHA256")
hmac.init(keySpec)
hmac.update(url.protocol.toByteArray(Charsets.UTF_8))
hmac.update(url.host.toByteArray(Charsets.UTF_8))
hmac.update(url.path.toByteArray(Charsets.UTF_8))
hmac.update(authHeaderValue.toByteArray(Charsets.UTF_8))
return hmac.doFinal().toHex()
}
请记住,这是一个简单的解决方案,但即使是复杂的解决方案也容易受到攻击者使用的 Frida 脚本的攻击。
深度安全
所以,我正在寻找任何解决方法或适当的解决方案。任何帮助将不胜感激。
安全就是要尽可能多地添加层,以使攻击者花费时间来克服所有这些层,并提高攻击者所需技能集的标准。
因此,使用 C 代码隐藏秘密(如解密密钥)将加密的秘密存储在 Android 密钥库中会丢弃脚本孩子,但会使您容易受到知道如何使用 Frida 脚本挂钩您的代码的攻击者的攻击。
在我的 Andorid 应用程序中,我使用少量密钥和令牌进行身份验证和初始化。
如果您正在尝试保护访问 API 的密钥,那么您可以阅读 my answer 到 this question 以了解实施移动应用程序证明概念将使您无需存储秘密即可访问您的 API 服务器。出于初始化目的,我建议您将此逻辑移至后端,因为任何应用内决策都可以通过检测框架修改/绕过
还可以考虑对您的所有代码库使用强混淆技术,这将在攻击者对您的移动应用进行逆向工程的步骤中增加另一层难度。
您想加倍努力吗?
在回答安全问题时,我总是喜欢参考 OWASP 基金会的出色工作。
对于移动应用
OWASP Mobile Security Project - Top 10 risks
OWASP 移动安全项目是一个集中资源,旨在为开发人员和安全团队提供构建和维护安全移动应用程序所需的资源。通过该项目,我们的目标是对移动安全风险进行分类并提供开发控制以减少其影响或被利用的可能性。
OWASP - Mobile Security Testing Guide:
移动安全测试指南 (MSTG) 是一本用于移动应用安全开发、测试和逆向工程的综合手册。
对于 APIS
OWASP API Security Top 10
OWASP API 安全项目旨在通过强调不安全 API 的潜在风险并说明如何降低这些风险,为软件开发人员和安全评估人员提供价值。为了实现这一目标,OWASP API 安全项目将创建和维护一份 API 安全风险前 10 名文档,以及一个文档门户,用于在创建或评估 API 时提供最佳实践。