你的问题
Android 应用程序中的静态信息在哪里安全保存?
无论您在何处以及如何存储它们,因为从您发布移动应用程序的那一刻起,其中的任何秘密现在都属于公共领域。
我也尝试过密码学,但随后我还必须存储密钥以进行解密。
您可以使用 Android 中的 JNI/NDK 接口将其隐藏在 C 代码中,从而使其难以通过静态分析进行逆向工程,就像我在本文中所做的那样货币转换器演示 https://github.com/approov/currency-converter-demo/tree/0.4.0/mobile-app/android/app/src/main/cpp存储库,但是如果攻击者无法以这种方式对其进行逆向工程,他将在运行时使用仪器框架来完成此操作,一种流行的框架是Frida https://www.frida.re/:
将您自己的脚本注入黑盒进程。挂钩任何函数、监视加密 API 或跟踪私有应用程序代码,无需源代码。编辑,点击保存,然后立即看到结果。全部无需编译步骤或程序重新启动。
另一种选择是尝试在运行时计算秘密密钥,但随后 Frida 将再次挂钩执行此操作的函数并从其返回值中提取秘密。
在运行时计算 HMAC 的基本代码示例可以在ShipFast 演示 https://github.com/approov/shipfast-api-protection/blob/b45b4ced2a77a4c140fa29bc09b941b8a6c534c6/app/android/kotlin/ShipFast/app/src/main/java/com/criticalblue/shipfast/api/RestAPI.kt#L240-L282 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 脚本来挂钩您的代码的攻击者的攻击。
在我的 Android 应用程序中,我使用很少的密钥和令牌进行身份验证和初始化。
如果您正在尝试保护访问 API 的密钥,那么您可以阅读我的答案 https://stackoverflow.com/questions/60559419/how-to-secure-an-api-rest-for-mobile-app-if-sniffing-requests-gives-you-the-k/60605789#60605789 to 这个问题 https://stackoverflow.com/questions/60559419/how-to-secure-an-api-rest-for-mobile-app-if-sniffing-requests-gives-you-the-k/60605789#60605789了解实施移动应用程序证明概念将使您无需存储密钥即可访问 API 服务器。出于初始化目的,我建议您将此逻辑移至后端,因为任何应用程序内的决策都可以使用检测框架进行修改/绕过
还可以考虑对所有代码库使用强大的混淆技术,这将为攻击者对您的移动应用程序进行逆向工程增加另一层难度。
您想加倍努力吗?
在回答安全问题时,我总是喜欢参考 OWASP 基金会的出色工作。
对于移动应用程序
OWASP 移动安全项目 - 十大风险 https://www.owasp.org/index.php/OWASP_Mobile_Security_Project#Top_Ten_Mobile_Risks
OWASP 移动安全项目是一个集中资源,旨在为开发人员和安全团队提供构建和维护安全移动应用程序所需的资源。通过该项目,我们的目标是对移动安全风险进行分类并提供开发控制以减少其影响或被利用的可能性。
OWASP - 移动安全测试指南 https://github.com/OWASP/owasp-mstg:
移动安全测试指南 (MSTG) 是移动应用安全开发、测试和逆向工程的综合手册。
For APIS
OWASP API 安全性前 10 名 https://github.com/OWASP/API-Security
OWASP API 安全项目旨在通过强调不安全 API 的潜在风险并说明如何减轻这些风险,为软件开发人员和安全评估人员提供价值。为了实现这一目标,OWASP API 安全项目将创建并维护十大 API 安全风险文档,以及创建或评估 API 时最佳实践的文档门户。