ANDROID 共享首选项或 ANDROID KEYSTORE?
我现在正在做的是将证书和密钥文件存储在资产/证书中,通过输入获取密钥和基本身份验证的密码,然后保存在 SharedPreferences 中。这可能不安全。
是的,如果您不加密它们,则根本不安全。
Android Shared Preferences
SharedPreferences 对象指向包含键值对的文件,并提供简单的方法来读取和写入它们。每个 SharedPreferences 文件都由框架管理,可以是私有的,也可以是共享的。
使用 Android 密钥库加密共享首选项
我最关心的是这两个 .pem 文件。我阅读了很多关于将它们保存在 Android 密钥库中的信息,但对此不太确定
要加密共享首选项,我们需要使用 EncryptedSharedPreferences 类并将加密密钥存储在 Android 密钥库中,正如您已经阅读的那样。
Android Hardware-backed Keystore
片上系统 (SoC) 中可信执行环境的可用性为 Android 设备提供了一个机会,可以为 Android 操作系统、平台服务甚至第三方应用提供硬件支持的强大安全服务.
为了帮助您更安全地处理数据,Android 为您提供了Security Library:
安全库提供与读取和写入静态数据以及密钥创建和验证相关的安全最佳实践的实现。
来自 Android 文档的示例:
他们只提供Kotlin 或Java 中的示例,没有Flutter,因此我在这里复制粘贴Kotlin 的示例。
写:
// Although you can define your own key generation parameter specification, it's
// recommended that you use the value specified here.
val keyGenParameterSpec = MasterKeys.AES256_GCM_SPEC
val masterKeyAlias = MasterKeys.getOrCreate(keyGenParameterSpec)
// Creates a file with this name, or replaces an existing file
// that has the same name. Note that the file name cannot contain
// path separators.
val fileToWrite = "my_sensitive_data.txt"
val encryptedFile = EncryptedFile.Builder(
File(DIRECTORY, fileToWrite),
context,
masterKeyAlias,
EncryptedFile.FileEncryptionScheme.AES256_GCM_HKDF_4KB
).build()
val fileContent = "MY SUPER-SECRET INFORMATION"
.toByteArray(StandardCharsets.UTF_8))
encryptedFile.openFileOutput().apply {
write(fileContent)
flush()
close()
}
阅读
// Although you can define your own key generation parameter specification, it's
// recommended that you use the value specified here.
val keyGenParameterSpec = MasterKeys.AES256_GCM_SPEC
val masterKeyAlias = MasterKeys.getOrCreate(keyGenParameterSpec)
val context = applicationContext
val fileToRead = "my_sensitive_data.txt"
val encryptedFile = EncryptedFile.Builder(
File(DIRECTORY, fileToRead),
context,
masterKeyAlias,
EncryptedFile.FileEncryptionScheme.AES256_GCM_HKDF_4KB
).build()
val inputStream = encryptedFile.openFileInput()
val byteArrayOutputStream = ByteArrayOutputStream()
var nextByte: Int = inputStream.read()
while (nextByte != -1) {
byteArrayOutputStream.write(nextByte)
nextByte = inputStream.read()
}
val plaintext: ByteArray = byteArrayOutputStream.toByteArray()
逆向工程
将证书存储在资产中,我担心它会被逆向工程。
无论你如何存储它们,它们都可以被逆向工程,即使使用我上面提到的方法。
在这种情况下,攻击者将求助于使用检测框架并在运行时挂钩到检索和解密 pem 证书的代码,然后将它们提取到他的命令和控制服务器,然后他可以从那里自动攻击您的后端。
Instrumentation 框架的一个示例是Frida:
将您自己的脚本注入黑盒进程。挂钩任何功能、监视加密 API 或跟踪私有应用程序代码,无需源代码。编辑,点击保存,立即查看结果。所有这些都无需编译步骤或程序重新启动。
请记住,您希望在移动应用中保密的任何内容实际上都是公开的,因为它只需要攻击者使用大量开源工具来简化此任务。
可能的解决方案
工作正常,但我想确保它不能从其他应用程序中提取。
正如您已经意识到从您的移动应用程序中提取 pem 文件并非不可能,您只能让它变得更加困难。
您的问题的一个可能解决方案是让您的后端知道他何时可以高度信任请求确实来自您的移动应用程序,从而允许它拒绝从您的移动应用程序中提取的 pem 文件的请求从其他地方使用。
我建议您阅读我针对问题提出的answer如何保护移动应用的 API REST?。
我要求您首先了解 谁 与 什么 访问您的后端之间的区别,因为这是开发人员之间的常见误解,导致他们相信用户身份验证足以证明 what 正在向后端发出请求,而实际上它只是证明 谁 是请求中的用户。话虽如此,我仍然建议使用足以满足移动应用用例及其用户群的强大用户身份验证解决方案。
在您清楚了解该差异后,您可以继续阅读其余答案,看看保护 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 时提供最佳实践。