Encrypt information on Android devices (protect reasonably from access by user) - android

We are in the making of an Android app, a quiz game, which we would like to cache questions + answers for when the user is offline. The problem with this is that we would need to withhold this data from the user until she has answered the questions. Otherwise, cheating would be very easy, which would harm the game. One could then extract all questions + answers and automatically submit answers to the server API.
The most convenient way would be to retrieve a key or secret from our server at installation time, hide it "somewhere", and use it for communication with the server, and also for the encryption of questions + answers in storage. But obviously, hiding it "somewhere" is not a secure concept.
I have researched a bit, and it seems that reliable encryption is not possible in such cases, because the app has to "know" the secret (be it a certificate, passphrase + salt, or whatever) or at least where it can be found, and this can be extracted by decompilation. However, we would be fine with it being hard enough to do.
The question is: Do you know of a way to make it prohibitively hard for regular users to retrieve a secret from the APK - i.e., make it near-impossible to write an automated key-extractor?
My best guesses so far:
Hide some information in the database and use it as salt for the key
Add several bits of information from the device as salt (IMEI, email address, serial number,...) - perhaps together with obfuscation the way how the salt is applied might be hard to obtain?

You could use a separate key for each question, which depends on the answer to the previous question. So it's impossible to decrypt question 2 unless you've already answered question 1.

Related

Android how to obfuscate static string constants? [duplicate]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 3 years ago.
Improve this question
Most app developers will integrate some third party libraries into their apps. If it's to access a service, such as Dropbox or YouTube, or for logging crashes. The number of third party libraries and services is staggering. Most of those libraries and services are integrated by somehow authenticating with the service, most of the time, this happens through an API key. For security purposes, services usually generate a public and private, often also referred to as secret, key. Unfortunately, in order to connect to the services, this private key must be used to authenticate and hence, probably be part of the application.
Needless to say, that this faces in immense security problem. Public and private API keys can be extracted from APKs in a matter of minutes and can easily be automated.
Assuming I have something similar to this, how can I protect the secret key:
public class DropboxService {
private final static String APP_KEY = "jk433g34hg3";
private final static String APP_SECRET = "987dwdqwdqw90";
private final static AccessType ACCESS_TYPE = AccessType.DROPBOX;
// SOME MORE CODE HERE
}
What is in your opinion the best and most secure way to store the private key? Obfuscation, encryption, what do you think?
As it is, your compiled application contains the key strings, but also the constant names APP_KEY and APP_SECRET. Extracting keys from such self-documenting code is trivial, for instance with the standard Android tool dx.
You can apply ProGuard. It will leave the key strings untouched, but it will remove the constant names. It will also rename classes and methods with short, meaningless names, where ever possible. Extracting the keys then takes some more time, for figuring out which string serves which purpose.
Note that setting up ProGuard shouldn't be as difficult as you fear. To begin with, you only need to enable ProGuard, as documented in project.properties. If there are any problems with third-party libraries, you may need to suppress some warnings and/or prevent them from being obfuscated, in proguard-project.txt. For instance:
-dontwarn com.dropbox.**
-keep class com.dropbox.** { *; }
This is a brute-force approach; you can refine such configuration once the processed application works.
You can obfuscate the strings manually in your code, for instance with a Base64 encoding or preferably with something more complicated; maybe even native code. A hacker will then have to statically reverse-engineer your encoding or dynamically intercept the decoding in the proper place.
You can apply a commercial obfuscator, like ProGuard's specialized sibling DexGuard. It can additionally encrypt/obfuscate the strings and classes for you. Extracting the keys then takes even more time and expertise.
You might be able to run parts of your application on your own server. If you can keep the keys there, they are safe.
In the end, it's an economic trade-off that you have to make: how important are the keys, how much time or software can you afford, how sophisticated are the hackers who are interested in the keys, how much time will they want to spend, how much worth is a delay before the keys are hacked, on what scale will any successful hackers distribute the keys, etc. Small pieces of information like keys are more difficult to protect than entire applications. Intrinsically, nothing on the client-side is unbreakable, but you can certainly raise the bar.
(I am the developer of ProGuard and DexGuard)
Few ideas, in my opinion only first one gives some guarantee:
Keep your secrets on some server on internet, and when needed just grab them and use. If user is about to use dropbox then nothing stops you from making request to your site and get your secret key.
Put your secrets in jni code, add some variable code to make your libraries bigger and more difficult to decompile. You might also split key string in few parts and keep them in various places.
use obfuscator, also put in code hashed secret and later on unhash it when needed to use.
Put your secret key as last pixels of one of your image in assets. Then when needed read it in your code. Obfuscating your code should help hide code that will read it.
If you want to have a quick look at how easy it is to read you apk code then grab APKAnalyser:
http://developer.sonymobile.com/knowledge-base/tool-guides/analyse-your-apks-with-apkanalyser/
Another approach is to not have the secret on the device in the first place! See Mobile API Security Techniques (especially part 3).
Using the time honored tradition of indirection, share the secret between your API endpoint and an app authentication service.
When your client wants to make an API call, it asks the app auth service to authenticate it (using strong remote attestation techniques), and it receives a time limited (usually JWT) token signed by the secret.
The token is sent with each API call where the endpoint can verify its signature before acting on the request.
The actual secret is never present on the device; in fact, the app never has any idea if it is valid or not, it juts requests authentication and passes on the resulting token. As a nice benefit from indirection, if you ever want to change the secret, you can do so without requiring users to update their installed apps.
So if you want to protect your secret, not having it in your app in the first place is a pretty good way to go.
Old unsecured way:
Follow 3 simple steps to secure the API/Secret key (Old answer)
We can use Gradle to secure the API key or Secret key.
1. gradle.properties (Project properties): Create variable with key.
GoogleAPIKey = "Your API/Secret Key"
2. build.gradle (Module: app) : Set variable in build.gradle to access it in activity or fragment. Add below code to buildTypes {}.
buildTypes.each {
it.buildConfigField 'String', 'GoogleSecAPIKEY', GoolgeAPIKey
}
3. Access it in Activity/Fragment by app's BuildConfig:
BuildConfig.GoogleSecAPIKEY
Update:
The above solution is helpful in the open-source project to commit over Git. (Thanks to David Rawson and riyaz-ali for your comment).
As per Matthew and Pablo Cegarra's comments, the above way is not secure and Decompiler will allow someone to view the BuildConfig with our secret keys.
Solution:
We can use NDK to Secure API Keys. We can store keys in the native C/C++ class and access them in our Java classes.
Please follow this blog to secure API keys using NDK.
A follow-up on how to store tokens securely in Android
Adding to #Manohar Reddy solution, firebase Database or firebase RemoteConfig (with Null default value) can be used:
Cipher your keys
Store it in firebase database
Get it during App startup or whenever required
decipher keys and use it
What is different in this solution?
no credintials for firebase
firebase access is protected so only app with signed certificate have
privilege to make API calls
ciphering/deciphering to prevent middle man interception. However
calls already https to firebase
The App-Secret key should be kept private - but when releasing the app
they can be reversed by some guys.
for those guys it will not hide, lock the either the ProGuard the code. It is a refactor and some payed obfuscators are inserting a few bitwise operators to get back the jk433g34hg3
String. You can make 5 -15 min longer the hacking if you work 3 days :)
Best way is to keep it as it is, imho.
Even if you store at server side( your PC ) the key can be hacked and printed out. Maybe this takes the longest? Anyhow it is a matter of few minutes or a few hours in best case.
A normal user will not decompile your code.
One possible solution is to encode the data in your app and use decoding at runtime (when you want to use that data). I also recommend to use progaurd to make it hard to read and understand the decompiled source code of your app . for example I put a encoded key in the app and then used a decode method in my app to decode my secret keys at runtime:
// "the real string is: "mypassword" ";
//encoded 2 times with an algorithm or you can encode with other algorithms too
public String getClientSecret() {
return Utils.decode(Utils
.decode("Ylhsd1lYTnpkMjl5WkE9PQ=="));
}
Decompiled source code of a proguarded app is this:
public String c()
{
return com.myrpoject.mypackage.g.h.a(com.myrpoject.mypackage.g.h.a("Ylhsd1lYTnpkMjl5WkE9PQ=="));
}
At least it's complicated enough for me. this is the way I do when I have no choice but store a value in my application. Of course we all know It's not the best way but it works for me.
/**
* #param input
* #return decoded string
*/
public static String decode(String input) {
// Receiving side
String text = "";
try {
byte[] data = Decoder.decode(input);
text = new String(data, "UTF-8");
return text;
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return "Error";
}
Decompiled version:
public static String a(String paramString)
{
try
{
str = new String(a.a(paramString), "UTF-8");
return str;
}
catch (UnsupportedEncodingException localUnsupportedEncodingException)
{
while (true)
{
localUnsupportedEncodingException.printStackTrace();
String str = "Error";
}
}
}
and you can find so many encryptor classes with a little search in google.
This example has a number of different aspects to it. I will mention a couple of points that I don't think have been explicitly covered elsewhere.
Protecting the secret in transit
The first thing to note is that accessing the dropbox API using their app authentication mechanism requires you to transmit your key and secret. The connection is HTTPS which means that you can't intercept the traffic without knowing the TLS certificate. This is to prevent a person intercepting and reading the packets on their journey from the mobile device to the server. For normal users it is a really good way of ensuring the privacy of their traffic.
What it is not good at, is preventing a malicious person downloading the app and inspecting the traffic. It is really easy to use a man-in-the-middle proxy for all traffic into and out of a mobile device. It would require no disassembly or reverse engineering of code to extract the app key and secret in this case due to the nature of the Dropbox API.
You could do pinning which checks that the TLS certificate you receive from the server is the one you expect. This adds a check to the client and makes it more difficult to intercept the traffic. This would make it harder to inspect the traffic in flight, but the pinning check happens in the client, so it would likely still be possible to disable the pinning test. It does make it harder though.
Protecting the secret at rest
As a first step, using something like proguard will help to make it less obvious where any secrets are held. You could also use the NDK to store the key and secret and send requests directly, which would greatly reduce the number of people with the appropriate skills to extract the information. Further obfuscation can be achieved by not storing the values directly in memory for any length of time, you can encrypt them and decrypt them just before use as suggested by another answer.
More advanced options
If you are now paranoid about putting the secret anywhere in your app, and you have time and money to invest in more comprehensive solutions, then you might consider storing the credentials on your servers (presuming you have any). This would increase the latency of any calls to the API, as it will have to communicate via your server, and might increase the costs of running your service due to increased data throughput.
You then have to decide how best to communicate with your servers to ensure they are protected. This is important to prevent all of the same problems coming up again with your internal API. The best rule of thumb I can give is to not transmit any secret directly because of the man-in-the-middle threat. Instead you can sign the traffic using your secret and verify the integrity of any requests that come to your server. One standard way of doing this is to compute an HMAC of the message keyed on a secret. I work at a company that has a security product that also operates in this field which is why this sort of stuff interests me. In fact, here is a blog article from one of my colleagues that goes over most of this.
How much should I do?
With any security advice like this you need to make a cost/benefit decision about how hard you want to make it for someone to break in. If you are a bank protecting millions of customers your budget is totally different to someone supporting an app in their spare time. It is virtually impossible to prevent someone from breaking your security, but in practice few people need all of the bells and whistles and with some basic precautions you can get a long way.
Whatever you do to secure your secret keys is not going to be a real solution. If developer can decompile the application there is no way to secure the key, hiding the key is just security by obscurity and so is code obfuscation. Problem with securing a secret key is that in order to secure it you have to use another key and that key needs to also be secured. Think of a key hidden in a box that is locked with a key. You place a box inside a room and lock the room. You are left with another key to secure. And that key is still going to be hardcoded inside your application.
So unless the user enters a PIN or a phrase there is no way to hide the key. But to do that you would have to have a scheme for managing PINs happening out of band, which means through a different channel. Certainly not practical for securing keys for services like Google APIs.
The most secure solution is to keep your keys on a server and route all requests needing that key through your server. That way the key never leaves your server, so as long as your server is secure then so is your key. Of course there is a performance cost with this solution.
The only true way to keep these private is to keep them on your server, and have the app send whatever it is to the server, and the server interacts with Dropbox. That way you NEVER distribute your private key in any format.
Keep the secret in firebase database and get from it when app starts ,
It is far better than calling a web service .
Ages old post, but still good enough. I think hiding it in an .so library would be great, using NDK and C++ of course. .so files can be viewed in a hex editor, but good luck decompiling that :P

Where should I place API keys in to be published app? [duplicate]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 3 years ago.
Improve this question
Most app developers will integrate some third party libraries into their apps. If it's to access a service, such as Dropbox or YouTube, or for logging crashes. The number of third party libraries and services is staggering. Most of those libraries and services are integrated by somehow authenticating with the service, most of the time, this happens through an API key. For security purposes, services usually generate a public and private, often also referred to as secret, key. Unfortunately, in order to connect to the services, this private key must be used to authenticate and hence, probably be part of the application.
Needless to say, that this faces in immense security problem. Public and private API keys can be extracted from APKs in a matter of minutes and can easily be automated.
Assuming I have something similar to this, how can I protect the secret key:
public class DropboxService {
private final static String APP_KEY = "jk433g34hg3";
private final static String APP_SECRET = "987dwdqwdqw90";
private final static AccessType ACCESS_TYPE = AccessType.DROPBOX;
// SOME MORE CODE HERE
}
What is in your opinion the best and most secure way to store the private key? Obfuscation, encryption, what do you think?
As it is, your compiled application contains the key strings, but also the constant names APP_KEY and APP_SECRET. Extracting keys from such self-documenting code is trivial, for instance with the standard Android tool dx.
You can apply ProGuard. It will leave the key strings untouched, but it will remove the constant names. It will also rename classes and methods with short, meaningless names, where ever possible. Extracting the keys then takes some more time, for figuring out which string serves which purpose.
Note that setting up ProGuard shouldn't be as difficult as you fear. To begin with, you only need to enable ProGuard, as documented in project.properties. If there are any problems with third-party libraries, you may need to suppress some warnings and/or prevent them from being obfuscated, in proguard-project.txt. For instance:
-dontwarn com.dropbox.**
-keep class com.dropbox.** { *; }
This is a brute-force approach; you can refine such configuration once the processed application works.
You can obfuscate the strings manually in your code, for instance with a Base64 encoding or preferably with something more complicated; maybe even native code. A hacker will then have to statically reverse-engineer your encoding or dynamically intercept the decoding in the proper place.
You can apply a commercial obfuscator, like ProGuard's specialized sibling DexGuard. It can additionally encrypt/obfuscate the strings and classes for you. Extracting the keys then takes even more time and expertise.
You might be able to run parts of your application on your own server. If you can keep the keys there, they are safe.
In the end, it's an economic trade-off that you have to make: how important are the keys, how much time or software can you afford, how sophisticated are the hackers who are interested in the keys, how much time will they want to spend, how much worth is a delay before the keys are hacked, on what scale will any successful hackers distribute the keys, etc. Small pieces of information like keys are more difficult to protect than entire applications. Intrinsically, nothing on the client-side is unbreakable, but you can certainly raise the bar.
(I am the developer of ProGuard and DexGuard)
Few ideas, in my opinion only first one gives some guarantee:
Keep your secrets on some server on internet, and when needed just grab them and use. If user is about to use dropbox then nothing stops you from making request to your site and get your secret key.
Put your secrets in jni code, add some variable code to make your libraries bigger and more difficult to decompile. You might also split key string in few parts and keep them in various places.
use obfuscator, also put in code hashed secret and later on unhash it when needed to use.
Put your secret key as last pixels of one of your image in assets. Then when needed read it in your code. Obfuscating your code should help hide code that will read it.
If you want to have a quick look at how easy it is to read you apk code then grab APKAnalyser:
http://developer.sonymobile.com/knowledge-base/tool-guides/analyse-your-apks-with-apkanalyser/
Another approach is to not have the secret on the device in the first place! See Mobile API Security Techniques (especially part 3).
Using the time honored tradition of indirection, share the secret between your API endpoint and an app authentication service.
When your client wants to make an API call, it asks the app auth service to authenticate it (using strong remote attestation techniques), and it receives a time limited (usually JWT) token signed by the secret.
The token is sent with each API call where the endpoint can verify its signature before acting on the request.
The actual secret is never present on the device; in fact, the app never has any idea if it is valid or not, it juts requests authentication and passes on the resulting token. As a nice benefit from indirection, if you ever want to change the secret, you can do so without requiring users to update their installed apps.
So if you want to protect your secret, not having it in your app in the first place is a pretty good way to go.
Old unsecured way:
Follow 3 simple steps to secure the API/Secret key (Old answer)
We can use Gradle to secure the API key or Secret key.
1. gradle.properties (Project properties): Create variable with key.
GoogleAPIKey = "Your API/Secret Key"
2. build.gradle (Module: app) : Set variable in build.gradle to access it in activity or fragment. Add below code to buildTypes {}.
buildTypes.each {
it.buildConfigField 'String', 'GoogleSecAPIKEY', GoolgeAPIKey
}
3. Access it in Activity/Fragment by app's BuildConfig:
BuildConfig.GoogleSecAPIKEY
Update:
The above solution is helpful in the open-source project to commit over Git. (Thanks to David Rawson and riyaz-ali for your comment).
As per Matthew and Pablo Cegarra's comments, the above way is not secure and Decompiler will allow someone to view the BuildConfig with our secret keys.
Solution:
We can use NDK to Secure API Keys. We can store keys in the native C/C++ class and access them in our Java classes.
Please follow this blog to secure API keys using NDK.
A follow-up on how to store tokens securely in Android
Adding to #Manohar Reddy solution, firebase Database or firebase RemoteConfig (with Null default value) can be used:
Cipher your keys
Store it in firebase database
Get it during App startup or whenever required
decipher keys and use it
What is different in this solution?
no credintials for firebase
firebase access is protected so only app with signed certificate have
privilege to make API calls
ciphering/deciphering to prevent middle man interception. However
calls already https to firebase
The App-Secret key should be kept private - but when releasing the app
they can be reversed by some guys.
for those guys it will not hide, lock the either the ProGuard the code. It is a refactor and some payed obfuscators are inserting a few bitwise operators to get back the jk433g34hg3
String. You can make 5 -15 min longer the hacking if you work 3 days :)
Best way is to keep it as it is, imho.
Even if you store at server side( your PC ) the key can be hacked and printed out. Maybe this takes the longest? Anyhow it is a matter of few minutes or a few hours in best case.
A normal user will not decompile your code.
One possible solution is to encode the data in your app and use decoding at runtime (when you want to use that data). I also recommend to use progaurd to make it hard to read and understand the decompiled source code of your app . for example I put a encoded key in the app and then used a decode method in my app to decode my secret keys at runtime:
// "the real string is: "mypassword" ";
//encoded 2 times with an algorithm or you can encode with other algorithms too
public String getClientSecret() {
return Utils.decode(Utils
.decode("Ylhsd1lYTnpkMjl5WkE9PQ=="));
}
Decompiled source code of a proguarded app is this:
public String c()
{
return com.myrpoject.mypackage.g.h.a(com.myrpoject.mypackage.g.h.a("Ylhsd1lYTnpkMjl5WkE9PQ=="));
}
At least it's complicated enough for me. this is the way I do when I have no choice but store a value in my application. Of course we all know It's not the best way but it works for me.
/**
* #param input
* #return decoded string
*/
public static String decode(String input) {
// Receiving side
String text = "";
try {
byte[] data = Decoder.decode(input);
text = new String(data, "UTF-8");
return text;
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return "Error";
}
Decompiled version:
public static String a(String paramString)
{
try
{
str = new String(a.a(paramString), "UTF-8");
return str;
}
catch (UnsupportedEncodingException localUnsupportedEncodingException)
{
while (true)
{
localUnsupportedEncodingException.printStackTrace();
String str = "Error";
}
}
}
and you can find so many encryptor classes with a little search in google.
This example has a number of different aspects to it. I will mention a couple of points that I don't think have been explicitly covered elsewhere.
Protecting the secret in transit
The first thing to note is that accessing the dropbox API using their app authentication mechanism requires you to transmit your key and secret. The connection is HTTPS which means that you can't intercept the traffic without knowing the TLS certificate. This is to prevent a person intercepting and reading the packets on their journey from the mobile device to the server. For normal users it is a really good way of ensuring the privacy of their traffic.
What it is not good at, is preventing a malicious person downloading the app and inspecting the traffic. It is really easy to use a man-in-the-middle proxy for all traffic into and out of a mobile device. It would require no disassembly or reverse engineering of code to extract the app key and secret in this case due to the nature of the Dropbox API.
You could do pinning which checks that the TLS certificate you receive from the server is the one you expect. This adds a check to the client and makes it more difficult to intercept the traffic. This would make it harder to inspect the traffic in flight, but the pinning check happens in the client, so it would likely still be possible to disable the pinning test. It does make it harder though.
Protecting the secret at rest
As a first step, using something like proguard will help to make it less obvious where any secrets are held. You could also use the NDK to store the key and secret and send requests directly, which would greatly reduce the number of people with the appropriate skills to extract the information. Further obfuscation can be achieved by not storing the values directly in memory for any length of time, you can encrypt them and decrypt them just before use as suggested by another answer.
More advanced options
If you are now paranoid about putting the secret anywhere in your app, and you have time and money to invest in more comprehensive solutions, then you might consider storing the credentials on your servers (presuming you have any). This would increase the latency of any calls to the API, as it will have to communicate via your server, and might increase the costs of running your service due to increased data throughput.
You then have to decide how best to communicate with your servers to ensure they are protected. This is important to prevent all of the same problems coming up again with your internal API. The best rule of thumb I can give is to not transmit any secret directly because of the man-in-the-middle threat. Instead you can sign the traffic using your secret and verify the integrity of any requests that come to your server. One standard way of doing this is to compute an HMAC of the message keyed on a secret. I work at a company that has a security product that also operates in this field which is why this sort of stuff interests me. In fact, here is a blog article from one of my colleagues that goes over most of this.
How much should I do?
With any security advice like this you need to make a cost/benefit decision about how hard you want to make it for someone to break in. If you are a bank protecting millions of customers your budget is totally different to someone supporting an app in their spare time. It is virtually impossible to prevent someone from breaking your security, but in practice few people need all of the bells and whistles and with some basic precautions you can get a long way.
Whatever you do to secure your secret keys is not going to be a real solution. If developer can decompile the application there is no way to secure the key, hiding the key is just security by obscurity and so is code obfuscation. Problem with securing a secret key is that in order to secure it you have to use another key and that key needs to also be secured. Think of a key hidden in a box that is locked with a key. You place a box inside a room and lock the room. You are left with another key to secure. And that key is still going to be hardcoded inside your application.
So unless the user enters a PIN or a phrase there is no way to hide the key. But to do that you would have to have a scheme for managing PINs happening out of band, which means through a different channel. Certainly not practical for securing keys for services like Google APIs.
The most secure solution is to keep your keys on a server and route all requests needing that key through your server. That way the key never leaves your server, so as long as your server is secure then so is your key. Of course there is a performance cost with this solution.
The only true way to keep these private is to keep them on your server, and have the app send whatever it is to the server, and the server interacts with Dropbox. That way you NEVER distribute your private key in any format.
Ages old post, but still good enough. I think hiding it in an .so library would be great, using NDK and C++ of course. .so files can be viewed in a hex editor, but good luck decompiling that :P
Keep the secret in firebase database and get from it when app starts ,
It is far better than calling a web service .

Preventing Multiple Votes from a single user, with anonymity

I have an Android application that allows users to post information to a database, via a java web server that I have code on.
Users are allowed to up/down vote said post. How do I prevent the same user from voting a plethora of times on the same post?
A few ideas I had:
Disabling locally via adding a local storage "key" for the post ID Unique Key. For instance, when the user votes up or down. It writes a key with the information of the type of vote and the Unique Identifier of the post on the user's local storage. Is this feasible with a lot of votes? Would it cause any sort of hard drive consumption/lag?
Storing a uniquely-generated key on the user's phone generated at application install. This key would be submitted to a new table in the database that associates posts with votes and the "user-key".
If you're expecting lots of information, a database is probably the way to go. Obviously this will use storage space, but not much. Writing to the db tends to be very fast in my experience.
The unique key would work fine too. That way would be more secure (depending on how you do it) since it would be harder to spoof it from the client. If you generate the key based on the user's Google account, or the device ID, you're in good shape. If you do it by some pseudorandom method then the user could still cast multiple votes by just clearing the app data and getting a new key.
If it's really important to prevent multiple votes, do it on the server. If it's not particularly important, do whichever method seems easier to you. You can also consider doing both, for the best of both worlds: immediate feedback to the user on a duplicate vote attempt (or just altering the UI to make it impossible), plus a backup validation on the server in case the user tries to get around the client check.

Secure Storage of Personal User Data on iOS Device

I just noticed this article about a mobile app that is storing user information in plaintext. I've paid attention to the idea of storing the user's password on the server (using a SHA-512 hash function), but I'm not clear on the best methods for storage of personal information at the device itself.
Let me be clear I am essentially only talking about user names and passwords. The data that my app interacts with is not at all sensitive, and I know that I can implement some sort of symmetric encryption/decryption on that data.
For user convenience purposes, I'd like to offer the user an option to store their user name and password locally so that they aren't required to enter it each time they use the app. But I know that user's tend to reuse the same password for many different purposes, which means that I need to take precautions to keep my user's passwords secure. Classic tension between convenience and security.
Is it just simply a terrible idea to ever store this information locally? Or are there relatively simple means to securely encrypt this? Do the iOS and Android O/S provide any help with this?
Not necessarily looking for exhaustive answers, but I'd really appreciate some topics to research, article links, books, etc. Thank you very much. If this is a redundant question, please direct me to any posts that give answers that are still considered current.
Thank you very much!
All data on the device is automatically encrypted by the device to some degree, using the device id as the key. This prevents data from easily being read by anything other than the device itself, or someone with the device id anyway.
There's another level of encryption that you can pile on that utilizes the passcode, called Data Protection, which prevents the data being read unless the passcode is entered.
You can manually enable data protection in your app by using NSFileManager to access files and setting the NSFileProtectionKey attribute to NSFileProtectionComplete. See: Implementing and Testing iOS data protection.
Note that the user must set their device to require a passcode, and the stronger the passcode, the more secure the data will be.
You may be able to easily enable data protection through the provisioning profile for your app, even if you don't use the NSFileManager class with NSFileProtectionComplete. See: Data Protection / NSFileProtectionComplete - successfully supported through entitlements.plist?
I still wouldn't store the password. Store a randomly generated session key that is created when they log in. At least you can expire those and it's not the plain text password.
Just a follow up to this post from a year ago. What I decided to do was to generate a random session key (similar to #Marcus Adams suggestion) but use that value as a salt. I then concatenate that session key with the user's chosen plaintext password and store this value on the device (if the user elects to store their password). i.e, the device stores this value:
device_hash = sha256(device_salt || plaintext)
That hashed value then becomes the string that I pass over HTTP to the server for validation. On the server side, I have a different salt value stored over there. When the server receives the device hash value, it has its own salt value which it concatenates to that string, and then performs its own hash. That final hash is the password that is stored in the server database. i.e., the server stores this string:
server_hash = sha256(server_salt || device_hash))
I think that this is a viable balance between security and convenience, particularly since I am only trying to protect the password, and not trying to encrypt the actual data that gets exchanged in the normal course of the app. If the user's device is compromised, no attacker can use a rainbow table or anything like that to reverse engineer the password since it is salted. SHA256 along with the long length of the password should eliminate a brute force attack if someone were truly motivated.
Curious if anyone has any criticisms of this approach.

Best practice for storing and protecting private API keys in applications [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 3 years ago.
Improve this question
Most app developers will integrate some third party libraries into their apps. If it's to access a service, such as Dropbox or YouTube, or for logging crashes. The number of third party libraries and services is staggering. Most of those libraries and services are integrated by somehow authenticating with the service, most of the time, this happens through an API key. For security purposes, services usually generate a public and private, often also referred to as secret, key. Unfortunately, in order to connect to the services, this private key must be used to authenticate and hence, probably be part of the application.
Needless to say, that this faces in immense security problem. Public and private API keys can be extracted from APKs in a matter of minutes and can easily be automated.
Assuming I have something similar to this, how can I protect the secret key:
public class DropboxService {
private final static String APP_KEY = "jk433g34hg3";
private final static String APP_SECRET = "987dwdqwdqw90";
private final static AccessType ACCESS_TYPE = AccessType.DROPBOX;
// SOME MORE CODE HERE
}
What is in your opinion the best and most secure way to store the private key? Obfuscation, encryption, what do you think?
As it is, your compiled application contains the key strings, but also the constant names APP_KEY and APP_SECRET. Extracting keys from such self-documenting code is trivial, for instance with the standard Android tool dx.
You can apply ProGuard. It will leave the key strings untouched, but it will remove the constant names. It will also rename classes and methods with short, meaningless names, where ever possible. Extracting the keys then takes some more time, for figuring out which string serves which purpose.
Note that setting up ProGuard shouldn't be as difficult as you fear. To begin with, you only need to enable ProGuard, as documented in project.properties. If there are any problems with third-party libraries, you may need to suppress some warnings and/or prevent them from being obfuscated, in proguard-project.txt. For instance:
-dontwarn com.dropbox.**
-keep class com.dropbox.** { *; }
This is a brute-force approach; you can refine such configuration once the processed application works.
You can obfuscate the strings manually in your code, for instance with a Base64 encoding or preferably with something more complicated; maybe even native code. A hacker will then have to statically reverse-engineer your encoding or dynamically intercept the decoding in the proper place.
You can apply a commercial obfuscator, like ProGuard's specialized sibling DexGuard. It can additionally encrypt/obfuscate the strings and classes for you. Extracting the keys then takes even more time and expertise.
You might be able to run parts of your application on your own server. If you can keep the keys there, they are safe.
In the end, it's an economic trade-off that you have to make: how important are the keys, how much time or software can you afford, how sophisticated are the hackers who are interested in the keys, how much time will they want to spend, how much worth is a delay before the keys are hacked, on what scale will any successful hackers distribute the keys, etc. Small pieces of information like keys are more difficult to protect than entire applications. Intrinsically, nothing on the client-side is unbreakable, but you can certainly raise the bar.
(I am the developer of ProGuard and DexGuard)
Few ideas, in my opinion only first one gives some guarantee:
Keep your secrets on some server on internet, and when needed just grab them and use. If user is about to use dropbox then nothing stops you from making request to your site and get your secret key.
Put your secrets in jni code, add some variable code to make your libraries bigger and more difficult to decompile. You might also split key string in few parts and keep them in various places.
use obfuscator, also put in code hashed secret and later on unhash it when needed to use.
Put your secret key as last pixels of one of your image in assets. Then when needed read it in your code. Obfuscating your code should help hide code that will read it.
If you want to have a quick look at how easy it is to read you apk code then grab APKAnalyser:
http://developer.sonymobile.com/knowledge-base/tool-guides/analyse-your-apks-with-apkanalyser/
Another approach is to not have the secret on the device in the first place! See Mobile API Security Techniques (especially part 3).
Using the time honored tradition of indirection, share the secret between your API endpoint and an app authentication service.
When your client wants to make an API call, it asks the app auth service to authenticate it (using strong remote attestation techniques), and it receives a time limited (usually JWT) token signed by the secret.
The token is sent with each API call where the endpoint can verify its signature before acting on the request.
The actual secret is never present on the device; in fact, the app never has any idea if it is valid or not, it juts requests authentication and passes on the resulting token. As a nice benefit from indirection, if you ever want to change the secret, you can do so without requiring users to update their installed apps.
So if you want to protect your secret, not having it in your app in the first place is a pretty good way to go.
Old unsecured way:
Follow 3 simple steps to secure the API/Secret key (Old answer)
We can use Gradle to secure the API key or Secret key.
1. gradle.properties (Project properties): Create variable with key.
GoogleAPIKey = "Your API/Secret Key"
2. build.gradle (Module: app) : Set variable in build.gradle to access it in activity or fragment. Add below code to buildTypes {}.
buildTypes.each {
it.buildConfigField 'String', 'GoogleSecAPIKEY', GoolgeAPIKey
}
3. Access it in Activity/Fragment by app's BuildConfig:
BuildConfig.GoogleSecAPIKEY
Update:
The above solution is helpful in the open-source project to commit over Git. (Thanks to David Rawson and riyaz-ali for your comment).
As per Matthew and Pablo Cegarra's comments, the above way is not secure and Decompiler will allow someone to view the BuildConfig with our secret keys.
Solution:
We can use NDK to Secure API Keys. We can store keys in the native C/C++ class and access them in our Java classes.
Please follow this blog to secure API keys using NDK.
A follow-up on how to store tokens securely in Android
Adding to #Manohar Reddy solution, firebase Database or firebase RemoteConfig (with Null default value) can be used:
Cipher your keys
Store it in firebase database
Get it during App startup or whenever required
decipher keys and use it
What is different in this solution?
no credintials for firebase
firebase access is protected so only app with signed certificate have
privilege to make API calls
ciphering/deciphering to prevent middle man interception. However
calls already https to firebase
The App-Secret key should be kept private - but when releasing the app
they can be reversed by some guys.
for those guys it will not hide, lock the either the ProGuard the code. It is a refactor and some payed obfuscators are inserting a few bitwise operators to get back the jk433g34hg3
String. You can make 5 -15 min longer the hacking if you work 3 days :)
Best way is to keep it as it is, imho.
Even if you store at server side( your PC ) the key can be hacked and printed out. Maybe this takes the longest? Anyhow it is a matter of few minutes or a few hours in best case.
A normal user will not decompile your code.
One possible solution is to encode the data in your app and use decoding at runtime (when you want to use that data). I also recommend to use progaurd to make it hard to read and understand the decompiled source code of your app . for example I put a encoded key in the app and then used a decode method in my app to decode my secret keys at runtime:
// "the real string is: "mypassword" ";
//encoded 2 times with an algorithm or you can encode with other algorithms too
public String getClientSecret() {
return Utils.decode(Utils
.decode("Ylhsd1lYTnpkMjl5WkE9PQ=="));
}
Decompiled source code of a proguarded app is this:
public String c()
{
return com.myrpoject.mypackage.g.h.a(com.myrpoject.mypackage.g.h.a("Ylhsd1lYTnpkMjl5WkE9PQ=="));
}
At least it's complicated enough for me. this is the way I do when I have no choice but store a value in my application. Of course we all know It's not the best way but it works for me.
/**
* #param input
* #return decoded string
*/
public static String decode(String input) {
// Receiving side
String text = "";
try {
byte[] data = Decoder.decode(input);
text = new String(data, "UTF-8");
return text;
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return "Error";
}
Decompiled version:
public static String a(String paramString)
{
try
{
str = new String(a.a(paramString), "UTF-8");
return str;
}
catch (UnsupportedEncodingException localUnsupportedEncodingException)
{
while (true)
{
localUnsupportedEncodingException.printStackTrace();
String str = "Error";
}
}
}
and you can find so many encryptor classes with a little search in google.
This example has a number of different aspects to it. I will mention a couple of points that I don't think have been explicitly covered elsewhere.
Protecting the secret in transit
The first thing to note is that accessing the dropbox API using their app authentication mechanism requires you to transmit your key and secret. The connection is HTTPS which means that you can't intercept the traffic without knowing the TLS certificate. This is to prevent a person intercepting and reading the packets on their journey from the mobile device to the server. For normal users it is a really good way of ensuring the privacy of their traffic.
What it is not good at, is preventing a malicious person downloading the app and inspecting the traffic. It is really easy to use a man-in-the-middle proxy for all traffic into and out of a mobile device. It would require no disassembly or reverse engineering of code to extract the app key and secret in this case due to the nature of the Dropbox API.
You could do pinning which checks that the TLS certificate you receive from the server is the one you expect. This adds a check to the client and makes it more difficult to intercept the traffic. This would make it harder to inspect the traffic in flight, but the pinning check happens in the client, so it would likely still be possible to disable the pinning test. It does make it harder though.
Protecting the secret at rest
As a first step, using something like proguard will help to make it less obvious where any secrets are held. You could also use the NDK to store the key and secret and send requests directly, which would greatly reduce the number of people with the appropriate skills to extract the information. Further obfuscation can be achieved by not storing the values directly in memory for any length of time, you can encrypt them and decrypt them just before use as suggested by another answer.
More advanced options
If you are now paranoid about putting the secret anywhere in your app, and you have time and money to invest in more comprehensive solutions, then you might consider storing the credentials on your servers (presuming you have any). This would increase the latency of any calls to the API, as it will have to communicate via your server, and might increase the costs of running your service due to increased data throughput.
You then have to decide how best to communicate with your servers to ensure they are protected. This is important to prevent all of the same problems coming up again with your internal API. The best rule of thumb I can give is to not transmit any secret directly because of the man-in-the-middle threat. Instead you can sign the traffic using your secret and verify the integrity of any requests that come to your server. One standard way of doing this is to compute an HMAC of the message keyed on a secret. I work at a company that has a security product that also operates in this field which is why this sort of stuff interests me. In fact, here is a blog article from one of my colleagues that goes over most of this.
How much should I do?
With any security advice like this you need to make a cost/benefit decision about how hard you want to make it for someone to break in. If you are a bank protecting millions of customers your budget is totally different to someone supporting an app in their spare time. It is virtually impossible to prevent someone from breaking your security, but in practice few people need all of the bells and whistles and with some basic precautions you can get a long way.
Whatever you do to secure your secret keys is not going to be a real solution. If developer can decompile the application there is no way to secure the key, hiding the key is just security by obscurity and so is code obfuscation. Problem with securing a secret key is that in order to secure it you have to use another key and that key needs to also be secured. Think of a key hidden in a box that is locked with a key. You place a box inside a room and lock the room. You are left with another key to secure. And that key is still going to be hardcoded inside your application.
So unless the user enters a PIN or a phrase there is no way to hide the key. But to do that you would have to have a scheme for managing PINs happening out of band, which means through a different channel. Certainly not practical for securing keys for services like Google APIs.
The most secure solution is to keep your keys on a server and route all requests needing that key through your server. That way the key never leaves your server, so as long as your server is secure then so is your key. Of course there is a performance cost with this solution.
The only true way to keep these private is to keep them on your server, and have the app send whatever it is to the server, and the server interacts with Dropbox. That way you NEVER distribute your private key in any format.
Ages old post, but still good enough. I think hiding it in an .so library would be great, using NDK and C++ of course. .so files can be viewed in a hex editor, but good luck decompiling that :P
Keep the secret in firebase database and get from it when app starts ,
It is far better than calling a web service .

Categories

Resources