简体   繁体   English

在 Android 应用程序中安全地保存 static 信息的位置?

[英]Where to keep static information securely in Android app?

In my Andorid app, am using few keys and tokens for authentication and initialisations.在我的 Andorid 应用程序中,我使用少量密钥和令牌进行身份验证和初始化。 I need to store these static keys somewhere in app securely.我需要将这些static 密钥安全地存储在应用程序的某个位置。 At the same time, I need to access it in code as well.同时,我也需要在代码中访问它。 I am aware of SharedPreference and Gradle variables, which right now I use.我知道 SharedPreference 和 Gradle 变量,现在我使用它们。 I have tried Cryptography as well, but then I will have to store the secretKey also for decryption.我也尝试过密码学,但是我还必须存储密钥以进行解密。
So, am searching for any workaround or proper solution.因此,我正在寻找任何解决方法或适当的解决方案。 Any help will be highly appreciated.任何帮助将不胜感激。

YOUR PROBLEM你的问题

Where to keep static information securely in Android app?在 Android 应用程序中安全地保存 static 信息的位置?

No matter where and how you store them, because from the moment you release your mobile app, any secret on it belongs now to the public domain.无论您将它们存储在何处以及如何存储,因为从您发布移动应用程序的那一刻起,其上的任何秘密现在都属于公共领域。

I have tried Cryptography as well, but then I will have to store the secretKey also for decryption.我也尝试过密码学,但是我还必须存储密钥以进行解密。

You can make this hard to be reverse engineered by static analysis by hiding it in the C code, using the JNI/NDK interface in Android, like I do in this Currency Converter Demo repo, but then if the attacker is not able to reverse engineer it this way, he will do it during run-time with an instrumentation framework, and a popular one is Frida :您可以通过 static 分析通过将其隐藏在 C 代码中,使用 Android 中的 JNI/NDK 接口进行逆向工程,从而使其难以被逆向工程,但如果攻击者无法演示此货币转换器演示这样,他将在运行时使用检测框架执行此操作,流行的框架是Frida

Inject your own scripts into black box processes.将您自己的脚本注入黑盒进程。 Hook any function, spy on crypto APIs or trace private application code, no source code needed.挂钩任何 function,监视加密 API 或跟踪私有应用程序代码,无需源代码。 Edit, hit save, and instantly see the results.编辑,点击保存,立即查看结果。 All without compilation steps or program restarts.所有这些都无需编译步骤或程序重新启动。

Another alternative it's to try to compute the secret keys at runtime, but then once more Frida will hook on the function that does this and extract the secret from it's return value.另一种选择是尝试在运行时计算密钥,但随后 Frida 将再次挂钩执行此操作的 function 并从其返回值中提取密钥。

A basic code example of computing an HMAC during run-time can be found the the ShipFast Demo repo:可以在ShipFast Demo repo 中找到在运行时计算 HMAC 的基本代码示例:

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()
    }

Bear in mind this is a simple solution, but even a sophisticated one would be vulnerable to Frida scripts used by an attacker.请记住,这是一个简单的解决方案,但即使是复杂的解决方案也容易受到攻击者使用的 Frida 脚本的攻击。

SECURITY IN DEPTH深度安全

So, am searching for any workaround or proper solution.因此,我正在寻找任何解决方法或适当的解决方案。 Any help will be highly appreciated.任何帮助将不胜感激。

Security is all about adding as many layers as you can afford in order to make it time consuming for an attacker to overcome all of them, and to raise the bar for the skill set necessary by an attacker.安全性就是尽可能多地添加层,以使攻击者花费时间来克服所有这些层,并提高攻击者所需技能集的标准。

So using C code to hide secrets, like the decryption keys, store encrypted secrets on the Android keystore will throw away the scripts kids, but will leave you vulnerable to attackers that know how to use Frida scripts to hook into your code.因此,使用 C 代码隐藏秘密,如解密密钥,将加密的秘密存储在 Android 密钥库中会丢弃脚本孩子,但会让您容易受到知道如何使用 Frida 脚本挂钩您的代码的攻击者的攻击。

In my Andorid app, am using few keys and tokens for authentication and initialisations.在我的 Andorid 应用程序中,我使用少量密钥和令牌进行身份验证和初始化。

If your are trying to secure the keys to access your API then you can read my answer to this question to understand that implementing the Mobile App Attestation concept will allow you to not need to store secrets to access your API server.如果您正在尝试保护访问 API 的密钥,那么您可以阅读这个问题的回答,以了解实施移动应用程序证明概念将使您无需存储秘密来访问您的 API 服务器。 For initializations purposes I would recommend that you move this logic to the backend, because any in app decisions can be modified/bypassed with instrumentation Frameworks出于初始化目的,我建议您将此逻辑移至后端,因为可以使用检测框架修改/绕过应用程序中的任何决策

Also consider using strong obfuscation techniques for all your code base, that will add another layer of difficulty in the attacker steps to reverse engineer your mobile app.还可以考虑对所有代码库使用强大的混淆技术,这将在攻击者对您的移动应用程序进行逆向工程的步骤中增加另一层难度。

DO YOU WANT TO GO THE EXTRA MILE?您想要额外的里程吗?

In any response to a security question I always like to reference the excellent work from the OWASP foundation.在回答安全问题时,我总是喜欢参考 OWASP 基金会的出色工作。

For Mobile Apps对于移动应用

OWASP Mobile Security Project - Top 10 risks OWASP 移动安全项目 - 十大风险

The OWASP Mobile Security Project is a centralized resource intended to give developers and security teams the resources they need to build and maintain secure mobile applications. OWASP 移动安全项目是一个集中资源,旨在为开发人员和安全团队提供构建和维护安全移动应用程序所需的资源。 Through the project, our goal is to classify mobile security risks and provide developmental controls to reduce their impact or likelihood of exploitation.通过该项目,我们的目标是对移动安全风险进行分类并提供开发控制以减少其影响或被利用的可能性。

OWASP - Mobile Security Testing Guide : OWASP - 移动安全测试指南

The Mobile Security Testing Guide (MSTG) is a comprehensive manual for mobile app security development, testing and reverse engineering.移动安全测试指南 (MSTG) 是移动应用安全开发、测试和逆向工程的综合手册。

For APIS对于 APIS

OWASP API Security Top 10 OWASP API 安全前 10 名

The OWASP API Security Project seeks to provide value to software developers and security assessors by underscoring the potential risks in insecure APIs, and illustrating how these risks may be mitigated. OWASP API 安全项目旨在通过强调不安全 API 中的潜在风险并说明如何减轻这些风险,为软件开发人员和安全评估人员提供价值。 In order to facilitate this goal, the OWASP API Security Project will create and maintain a Top 10 API Security Risks document, as well as a documentation portal for best practices when creating or assessing APIs.为了促进实现这一目标,OWASP API 安全项目将创建和维护前 10 名 API 安全风险文档,以及创建或评估 API 时的最佳实践文档门户。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM