问题
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.
回答1:
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.
回答2:
This is really a provisioning problem. You don't really want all your apps to be authenticated with the same key -- once it's leaked all apps installs are compromised.
If you really want to use certificate-based authentication, you'd better generate a key/certificate on first use and use that. That's easier said that done though, so you might want to consider using something like the FIDO2 API available in Android, if you really need strong authentication.
来源:https://stackoverflow.com/questions/62211772/store-client-certificate-and-key-pem-in-android-securely