在 Android 中安全地存储客户端证书和密钥 (.pem) [英] Store Client Certificate and key (.pem) in Android securely

查看:42
本文介绍了在 Android 中安全地存储客户端证书和密钥 (.pem)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在开发一个供内部使用的 Android 应用程序,用于向我们的服务器发送测试请求.身份验证是通过基本 + 客户端证书.我现在正在做的是将证书和密钥文件存储在资产/证书中,通过输入获取密钥和基本身份验证的密码,然后保存在 SharedPreferences 中.这可能不安全.我最关心的是两个 .pem 文件.我读了很多关于将它们保存在 Android Keystore 中的内容,但对此不太确定.是否可以安装"证书并在之后删除 pem 文件?在寻找解决方案时,我发现大部分时间都是应用程序自行生成证书的问题.但是我有两个 .pem 文件,需要使用它们来发送请求.

将证书存储在资产中,我担心它会被逆向工程.

现在的示例代码:

SecurityContext 上下文 = SecurityContext.defaultContext;ByteData cert = await rootBundle.load("assets/certs/xy.cert.pem");context.useCertificateChainBytes(cert.buffer.asUint8List());ByteData key = await rootBundle.load("assets/certs/xy.key.pem");最终存储 = FlutterSecureStorage();String passphrase = await storage.read(key: "passphrase");String basic = await storage.read(key: "basic");context.usePrivateKeyBytes(key.buffer.asUint8List(), password:passphrase);HttpClient客户端=新的HttpClient(上下文:上下文);var uri = "https://url.com";var 方法 = 'POST';var request = await client.openUrl(method,Uri.parse(uri));request.headers.set('Content-Type', 'application/json; charset=utf-8');request.headers.set("授权", 基本);

工作正常,但我想确保它不能从其他应用程序中提取.

可能应该提到它:我正在使用颤振,但不知何故并没有让它变得更容易.

解决方案

ANDROID SHARED PREFERENCES OR ANDROID KEYSTORE?

<块引用>

我现在正在做的是将证书和密钥文件存储在资产/证书中,通过输入获取密钥和基本身份验证的密码,然后保存在 SharedPreferences 中.这可能不安全.

是的,如果您不加密它们,则根本不安全.

Android 共享首选项

<块引用>

SharedPreferences 对象指向包含键值对的文件,并提供简单的方法来读取和写入它们.每个 SharedPreferences 文件都由框架管理,可以是私有的,也可以是共享的.

使用 Android 密钥库加密共享首选项

<块引用>

我最关心的是这两个 .pem 文件.我阅读了很多关于将它们保存在 Android 密钥库中的信息,但对此不太确定

要加密共享首选项,我们需要使用类 EncryptedSharedPreferences 并将加密密钥存储在您已经阅读过的 Android Keystore 中.

Android 硬件支持的密钥库

<块引用>

片上系统 (SoC) 中可信执行环境的可用性为 Android 设备提供了一个机会,可以为 Android 操作系统、平台服务甚至第三方应用提供硬件支持的强大安全服务.

为了帮助您更安全地处理数据,Android 为您提供了安全库:

<块引用>

安全库提供与读取和写入静态数据以及密钥创建和验证相关的安全最佳实践的实现.

来自 Android 文档的示例:

他们只提供 KotlinJava 中的示例,没有 Flutter,因此我将 Kotlin 的示例复制粘贴在这里.

:

//虽然您可以定义自己的密钥生成参数规范,但它是//建议您使用此处指定的值.val keyGenParameterSpec = MasterKeys.AES256_GCM_SPECval masterKeyAlias = MasterKeys.getOrCreate(keyGenParameterSpec)//创建一个具有此名称的文件,或替换现有文件//同名.注意文件名不能包含//路径分隔符.val fileToWrite = "my_sensitive_data.txt";val encryptedFile = EncryptedFile.Builder(文件(目录,fileToWrite),语境,masterKeyAlias,EncryptedFile.FileEncryptionScheme.AES256_GCM_HKDF_4KB).建造()val fileContent = 我的超级机密信息".toByteArray(StandardCharsets.UTF_8))encryptedFile.openFileOutput().apply {写(文件内容)冲洗()关闭()}

阅读

//虽然您可以定义自己的密钥生成参数规范,但它是//建议您使用此处指定的值.val keyGenParameterSpec = MasterKeys.AES256_GCM_SPECval masterKeyAlias = MasterKeys.getOrCreate(keyGenParameterSpec)val 上下文 = applicationContextval fileToRead = "my_sensitive_data.txt";val encryptedFile = EncryptedFile.Builder(文件(目录,文件读取),语境,masterKeyAlias,EncryptedFile.FileEncryptionScheme.AES256_GCM_HKDF_4KB).建造()val inputStream = encryptedFile.openFileInput()val byteArrayOutputStream = ByteArrayOutputStream()var nextByte: Int = inputStream.read()而(下一个字节!= -1){byteArrayOutputStream.write(nextByte)nextByte = inputStream.read()}val 明文:ByteArray = byteArrayOutputStream.toByteArray()

逆向工程

<块引用>

将证书存储在资产中,我担心它会被逆向工程.

无论你如何存储它们,它们都可以被逆向工程,即使使用我上面提到的方法.

在这种情况下,攻击者将求助于使用检测框架并在运行时挂钩到检索和解密 pem 证书的代码,然后将它们提取到他的命令和控制服务器,然后他可以从那里自动攻击您的后端.

Instrumentation 框架的一个例子是 Frid​​a:

<块引用>

将您自己的脚本注入黑盒进程.挂钩任何功能、监视加密 API 或跟踪私有应用程序代码,无需源代码.编辑,点击保存,立即查看结果.所有这些都无需编译步骤或程序重新启动.

请记住,您希望在移动应用中保密的任何内容实际上都是公开的,因为它只需要攻击者使用大量开源工具来简化此任务.

可能的解决方案

<块引用>

工作正常,但我想确保它不能从其他应用程序中提取.

正如您已经意识到从您的移动应用程序中提取 pem 文件并非不可能,您只能让它变得更加困难.

您的问题的一个可能解决方案是让您的后端知道他何时可以高度信任请求确实来自您的移动应用程序,从而允许它拒绝从您的移动应用程序中提取的 pem 文件的请求从其他地方使用.

我建议您阅读 答案我给出了如何保护移动应用的 API REST?.

我要求您首先了解 什么 访问您的后端之间的区别,因为这是开发人员之间的常见误解,导致他们相信用户身份验证足以证明 what 正在向后端发出请求,而实际上它只是证明 是请求中的用户.话虽如此,我仍然建议使用足以满足移动应用用例及其用户群的强大用户身份验证解决方案.

在您清楚了解该差异后,您可以继续阅读其余答案,看看保护 API 服务器部分中的建议是否足够,或者您需要选择移动设备应用证明概念,如可能的更好解决方案部分所述.

您想加倍努力吗?

在回答安全问题时,我总是喜欢参考 OWASP 基金会的宝贵工作:)

对于移动应用

OWASP 移动安全项目 - 十大风险

<块引用>

OWASP 移动安全项目是一个集中资源,旨在为开发人员和安全团队提供构建和维护安全移动应用程序所需的资源.通过该项目,我们的目标是对移动安全风险进行分类并提供开发控制以减少其影响或被利用的可能性.

OWASP - 移动安全测试指南:

<块引用>

移动安全测试指南 (MSTG) 是移动应用安全开发、测试和逆向工程的综合手册.

对于 APIS

OWASP API 安全前 10 名

<块引用>

OWASP API 安全项目旨在通过强调不安全 API 的潜在风险并说明如何降低这些风险,为软件开发人员和安全评估人员提供价值.为了实现这一目标,OWASP API 安全项目将创建和维护一份 API 安全风险前 10 名文档,以及一个文档门户,用于在创建或评估 API 时提供最佳实践.

I am developing an Android App for internal use to send test requests to our server. The Authentification is via Basic + Client Certificate. What I am doing right now is storing cert and key file in assets/certs, getting the passphrase for the key and Basic Auth via input and then saved in SharedPreferences. This is probably not safe. I am mostly concerned about the two .pem-files. I read a lot about saving them in the Android Keystore, but not really sure about that. Is it possible to "install" the certificates and delete the pem files afterwards? What I found most of the time while searching for a solution were issues with self generated certificates from the app. But what I have are two .pem-files, that need to be used to send the request.

With storing the certs in assets I am worried it can be reverse-engineered.

Example code for now:

SecurityContext context = SecurityContext.defaultContext;
ByteData cert = await rootBundle.load("assets/certs/xy.cert.pem");
context.useCertificateChainBytes(cert.buffer.asUint8List());
ByteData key = await rootBundle.load("assets/certs/xy.key.pem");
final storage = FlutterSecureStorage();
String passphrase = await storage.read(key: "passphrase");
String basic = await storage.read(key: "basic");
context.usePrivateKeyBytes(key.buffer.asUint8List(), password:passphrase);
HttpClient client = new HttpClient(context: context);
var uri = "https://url.com";
var method = 'POST';
var request = await client.openUrl(method,Uri.parse(uri));
request.headers.set('Content-Type', 'application/json; charset=utf-8');
request.headers.set("Authorization", basic);

Works fine, but I want to make sure it can't be extracted from other apps.

EDIT:

Probably should've mentioned it: I am working with flutter, which somehow does not make it easier.

解决方案

ANDROID SHARED PREFERENCES OR ANDROID KEYSTORE?

What I am doing right now is storing cert and key file in assets/certs, getting the passphrase for the key and Basic Auth via input and then saved in SharedPreferences. This is probably not safe.

Yes is not safe at all if you don't encrypt them.

Android Shared Preferences

A SharedPreferences object points to a file containing key-value pairs and provides simple methods to read and write them. Each SharedPreferences file is managed by the framework and can be private or shared.

Encrypted Shared Preferences with the Android Keystore

I am mostly concerned about the two .pem-files. I read a lot about saving them in the Android Keystore, but not really sure about that

To encrypt the Shared preferences we need to use the class EncryptedSharedPreferences and store the encryption key in the Android Keystore as you already have read about.

Android Hardware-backed Keystore

The availability of a trusted execution environment in a system on a chip (SoC) offers an opportunity for Android devices to provide hardware-backed, strong security services to the Android OS, to platform services, and even to third-party apps.

To help you working with data more securely Android provides you the Security Library:

The Security library provides an implementation of the security best practices related to reading and writing data at rest, as well as key creation and verification.

Examples from Android docs:

They only provide examples in Kotlin or Java, no Flutter, therefore I copy paste here the Kotlin ones.

Write:

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

Read

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

REVERSE ENGINEERING

With storing the certs in assets I am worried it can be reverse-engineered.

No matter how you store them, they can be reverse engineered, even with the above method I mentioned.

An attacker will resort in this case to use an instrumentation framework and hook at runtime into the code that retrieves and decrypts the pem certificates, and then extracting them to his command and control server, from where he can then automate attacks against your backend.

An example of an Instrumentation framework is 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. Edit, hit save, and instantly see the results. All without compilation steps or program restarts.

Remember that anything you want to keep private in a mobile app is in fact public, because it just needs an attacker to use the vast array of open source tools that make this tasks easy.

POSSIBLE SOLUTION

Works fine, but I want to make sure it can't be extracted from other apps.

As you already realized you cannot make impossible to extract the pem files from your mobile app, you can make it only more difficult.

A possible solution for your problem is to empower your backend to know when he can trust with high confidence that a request is coming indeed from your mobile app, thus allowing it to refuse requests where pem files extracted from your mobile app are being used from elsewhere.

I recommend you to read the answer I gave to the question How to secure an API REST for mobile app?.

I ask you to first understand the difference between who vs what is accessing your backend, because its a common misconception among developers, that led them to believe that user authentication is enough to attest what is doing the request to the backend, when in fact it just attests who is the user in the request. This being said I still recommend to use strong user authentication solutions that are adequate to the mobile app use case and user base of it.

After that difference is clear in your mind you can proceed to read the rest of the answer and see if the recommendations in the section Securing the API server are enough or you need to go for the Mobile App Attestation concept as described in the section A Possible Better Solution.

DO YOU WANT TO GO THE EXTRA MILE?

In any response to a security question I always like to reference the invaluable work from the OWASP foundation :)

For Mobile Apps

OWASP Mobile Security Project - Top 10 risks

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. 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:

The Mobile Security Testing Guide (MSTG) is a comprehensive manual for mobile app security development, testing and reverse engineering.

For APIS

OWASP API Security Top 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. 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.

这篇关于在 Android 中安全地存储客户端证书和密钥 (.pem)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆