Is it possible to obtain secret keys embedded in a mobile app - android

I have a set of rest services exposed on a public host. There are mobile apps (android, iOS and windows) that will be consuming these services. For authentication purpose, I am using a secret key that has been shared with these apps and when they hit the services, the sent key is first matched with the actual key and services are served only when the key matches. My question is that is it possible for a hacker to reverse engineer the mobile apps and obtain that secret key (so that he can misuse the web services)? If yes, then how easy is it to do that and what is the solution to this problem?

The thing is how you are saving the secret key in your app .Now there can be many things
Encrypt you key
Use progaurd
Use private but not default shared-preferences(If saving the key in preferences)
Use HTTPS instead of HTTP
These are some ways with which you can secure your key and make it difficult to reverse the process, but again nothing is completely secure but my doing these steps you can make the much difference .

For iOS use the Keychain to securely save the key. There is a Keychain in Android but it works somewhat differently.
Use https to secure the commutations of the key to the server.
Consider an authentication scheme such as CHAP.

Related

Android - Best way to hide API clientId & clientSecret

I would like to have your opinion on the best way to hide an API key and secret key.
I found 2 ways :
Use NDK like that : https://medium.com/#abhi007tyagi/storing-api-keys-using-android-ndk-6abb0adcadad
Use Gradle like that : http://www.techjini.com/blog/securing-api-key-and-secret-key-in-android
I know that risk 0 does not exist but what is the most secure solution ?
Thank in advance
The NDK seems like your best bet, although not being 100% secure, but it sure is hard to reverse engineer. The gradle way doesn't seem secure at all.
For obfuscation and encryption purposes, you could also take advantage of DexGuard.
To hide secret keys in an Android app, we have developed a free open source alternative to Dexguard. Our hidden-secrets-gradle-plugin uses the NDK and XOR operator to obfuscate keys to prevent reverse engineering.
You can optionally provide a custom encoding/decoding algorithm to improve the security of your key.
Access to the plugin and all the details : https://github.com/klaxit/hidden-secrets-gradle-plugin
The best to secure the key is by not putting your keys in app, for that purpose if you are using a server that is highly secure (eg. Amazon Server) then put your keys on server and access them on run time. And also apply public/private encryption on both app and server side.
But if you want to stay with the app then using "NDK" or using "Proguard" both are highly secure mechanisms on app level.
If you are using oAuth to get a token you can setup a server with the client id and client secret on the your server. Your application gets the oAuth token from your server. This way you do not have to put the client id or client secret in your application that the user downloads and runs.

Securing Data Via Fingerprint Verification

I'm looking into ways to secure data on mobile via fingerprint verification.
The situtation on iOS seems fairly straight-forward by securing data in the Keychain via Touch.
But can something like this be done on Android where a piece of data is secured via a fingerprint? Or would we have to handle the association of data and fingerprint internally within the app?
UPDATE:
So having done a little bit more reading on this on Android I'm assuming the best way of doing this would be to encrypt the data within the app but secure the key being used with FingerprintManager and the Android Keystore?
Yes, you're heading into the right direction ;-)
Basically the Keystore is just for creating / storing key material and cannot be compared to something like the SharedPreferences. You could use the Keystore APIs to create a new cryptographic key which requires user authentication and with the generated key you could then en-/decrypt data. In order to access the key inside the Keystore the user needs to authenticate (e.g. through fingerprint authentication).
I have created a demo project for the new Keystore APIs (including fingerprint authentication) which you can find on GitHub: https://github.com/flschweiger/SafeApp

Store client secret securely

I know that a public client shouldn't use a client secret because, no matter how much you obfuscate it, it won't be protected from reverse engineering.
But, the people in charge of the service I am authenticating to don't want to/can't change it. So, I need to store the client secret and try to protect it from reverse engineering as much as I can.
So, I thought of encrypting it using at build time using gradle and store it in a file. Then, when I need it at run time I decrypt it. But now I have to solve the problem of how to store the encryption key...
I don't know much about security, so, I don't know if this can be solved, or if Android (min sdk 15) provides any mechanism for this kind of scenarios.
Any idea?
This article suggests these options, from less to more secure:
Store in cleartext
Store encrypted using a symmetric key
Using the Android Keystore
Store encrypted using asymmetric keys
Probably, using a combination of #4 and some way to univocally identify the device would be secure enough
Maybe the best option is to use NDK because it can not be decompiled, like Godfrey Nolan points here
Here is a resource I found useful that helped me to implement it link to the resource
Cheers
As you said, whatever you do, how much you try to hide your key, you can not hide it 100%.
But, if you want to make reverse engineer's work harder;
Firstly obfuscate your client (I guess you already do).
Secondly, do not put your key into the client hard-coded. Receive the key after login or user opened the application. And deliver secret key to the client over SSL. Store the secret as byte array and do not save it into the client. Just store in the memory.
These steps do not guarantee the safety of the secret key, but makes reverse engineer's job really hard.
You can also try Dexguard to obfuscate and encrypt the data. Dexguard is made by the same guy that developed proguard.
#Semih's answer was on the right track. The secret key part is what needs to be expanded upon.
The secret key is between the application and the gateway server not to the underlying services.
The gateway server is responsible for converting that key to something specific for the services.
The secret key is built using the following after the login process is complete
the server generates a key pair specific for the client logging in.
The server's public key is sent for encryption specific for the client logging in
the app will generate a key pair for it's own purposes
the app will send the public key encrypted with the server's public key
the server will validate the public key is signed with their public key.
Any future requests would involve the following
All data being sent from client to the server would be encrypted using JWT the message would be signed by the app's private key and encrypted using the server's public key.
The problem is securing #1 anyone can login and get the process started, so how would you prevent that? The only way I can think of is to do a CAPTCHA check on the login.
The solution pushes the storage of the client secrets to the server rather than on the app itself and protecting it using the app's credentials.

What is the preferred way of using AWS (specifically S3) from mobile apps?

Adding the AWS access key and secret key directly in app code is definitely not a good approach, primarily because the app resides on the users device (unlike server side code), and can be reverse engineered to get the credentials, which can then be misused.
Though I find this information everywhere, but am unable to find a definitive solution to this problem. What are my options? I read about the token vending machine architecture for temporary credentials, but I am not convinced that it is any better. If I can reverse engineer the secret key, then I can reverse engineer the code which requests for temporary credentials. And once I have a set of temporary credentials to access S3, I am as good as if I had the key. I can request the temporary credentials again and again, even if they expire pretty quickly. To summarize, if an app can do something, I can do the same as a malicious user. If anything, the TVM can be a bit better at management (rotating credentials, and changing key in case of breach, etc.). Please note we can put the same access restrictions on the secret key, as we plan to do in case of TVM temporary credentials.
Additionally, if Amazon doesn't want people to use the secret key directly in the App, why don't they block it in their SDK, and enforce TVM or the correct solution. If you will leave a path, people are going to use it. I read several articles like these, and wonder why?: http://blog.rajbala.com/post/81038397871/amazon-is-downloading-apps-from-google-play-and
I am primarily from web background, so my understanding of this may be a bit flawed. Please help me understand if this is better, and whether there is a perfect (or may be good) solution available to this problem.
PS: Is there a rails implementation of TVM?
Embedding S3 keys in App code is very risky. Anyone can easily get that key from your app code (no reverse engineering or high skill set required), even if that is stored encrypted it is still compromised just that someone need to try harder (depending on how do you encrypt).
I hope that you understand the advantages of using temporary credentials to access Amazon (S3 etc) resources (mainly security + some others like no app update etc). I think you are more confused about the process to get the temporary credentials from TVM and how that is safer than embedding keys in code.
Every client using TVM first need to register with the TVM server implementation hosted by you. The communication between App (using TVM client) and TVM server is over SSL.
First the app register with TVM by providing UUID and a secret key. Please note that the secret key is not embedded in App code (which I think is main reason for your confusion) but generated randomly (using SecRandomCopyBytes which generates an array of cryptographically secure random bytes) at the time of registration (and hex encoded).
Once the device is registered successfully with TVM, the client TVM store the generated UDID and secret key in a storage called Keychain in iOS and Shared Preferences in Android. The keychain in iOS is the shared storage provided by iOS to securely (encrypted) store information (mainly keys, password etc).
After registration and UDID/Secret Key storage, App can get the token from TVM by sending the UDID, cryptographic signature, and a timestamp. The cryptographic signature is an HMAC hash generated from the timestamp using the secret key. The TVM can use the UDID to lookup the secret key and uses it to verify the signature. The TVM then responds by sending back temporary credentials, which are encrypted using the secret key (uses AES). The application decrypts the temporary credentials using the key and can then use them to access any AWS services for which the temporary credentials are authorized. Eventually, the expiration time of these temporary credentials will be reached, at which point the application can get the fresh temporary credentials, if required.
I am not sure how signed URLs relate to TVM, because I don't understand the concepts 100% but signed URLs really solved the problem for me. I needed a mechanism that would feed web app and mobile app data without allowing for misuse of the credentials. Putting the key in the code is indeed a very bad idea as it may generate a huge bill for the company.
After 3 days of extensive research, I found a simple and, what seems to be, a reliable and relatively safe solution: signed URLs. The idea is, that a very light-weight back-end can generate a temporary URL that will grant the user access to the specific resource for a limited time. So the idea is simple:
the user asks our back-end with a Rest call that he wants a specific resource
the back-end is already authorized with AWS S3
the back-end generates a temporary URL for the user and sends it in the Rest response
the user uses the URL to fetch the data directly from the AWS
A plug-and-play Python implementation can be found here and with a slight modification that I had to use: here.
Of course one more thing to figure out would be how do we authorize the user before we know that we can grant it the URL but that's another pair of shoes.
You should ideally use Cognito Identity for achieving this along with appropriate policies. It should be used with S3TransferUtility and S3TransferManager in iOS and Android SDKs. That would allow for background uploads and downloads as well. Cognito vends temporary credentials for access to AWS resources and is free. Also, you could federate it using UserPools or providers like Google, Facebook if you want secure access.
Thanks,
Rohan

which is the safest way to include a pair of key (public/private) in a apk

I'm developing an application for android and I have to maintain a secure communication with a server through a pair of private and public key. Which is the safest way to storage the private key in my apk? Obviously I'm going to obfuscate the code but I want more security. I have thought the following option:
If I create a native share library with the methods for sign the transaction information, The apk only have to contain the .so file and this file is in machine code, so the decompilation could be difficult, isn't it?
any ideas?
Thanks
Store the keypair in a keystore and include the keystore as a resource in your APK. Android tends to prefer the BouncyCastle Key Store (BKS) format. Keystores are specifically designed for this purpose.
Note that you should protect the keystore with a password and your application will need to know that password to access the keystore. So, you're left with needing to ask the user for a password to access the keystore or include the password in your code (obfuscate it to make it harder for an attacker to reverse engineer). If someone is going to the trouble of reverse engineering your application to recover your encrypted keystore and the password needed to access it, including that password in a compiled native library will not present much of an additional hurdle.
However, you may not need to do this anyway. If your goal is to protect/encrypt the data in transport to/from the server, use SSL/TLS. If you're not doing client-side authentication, your server needs an SSL certificate but your client does not; the protocol takes care of generating the encryption keys for you in a safe manner. If you do want the server to authenticate the client (make it so your server only talks to your clients), you'd need to install a client-side SSL certificate with your app ... this is the private key that you're probably thinking about.
I'll also point you to Application Security for the Android Platform. This book (disclaimer: I wrote the book) has an entire chapter talking about how to design secure Android app-to-server communications, with code examples to illustrate how to implement the appropriate protections. You may want to give it a read.
First of all, in order to implement secure communication between your client application and a server, conceptually speaking, you need only the public key of the server. That allows you to establish a one-way trust relation ship with the server and to establish a secure session, in which the identity of the server is guaranteed.
While certainly the above method does not provide two-way trust (the client cannot be identified to the server), when establishing the communication channel in most applications, this level of trust is not really required.
If your requirements are to provide client authentication to the server using public/private keys then things get more complicated because if you put the key in the apk, no matter how much you obfuscate it (including embedding it in a native library) it will only slow down a dedicated nefarious user.
The only way to store the private key with the client is to encrypt it. But then you have a similar issue of where to store the decrypt key. The easiest solution is to generate a public/private key pair for the user of the client application and ask the user to provide a symmetric encryption/decryption key (which the user will always have to type in) to decrypt the private key each time the user is using the application.
The alternative would be to use some kind of dedicated cryptographic hardware device similar to a smart card that would store the private key securely but you still have the problem of authorizing your application to read the key from the device (not to mention the complication of interfacing with said device).
Now, the question you have to ask yourself is this: "Who are you trying to prevent from reading the private key?" (of course after answering the other question: "Do you really need a public/private key pair for the client").

Categories

Resources