We're working on a fairly enterprise-y app right now, and the mandate has been that all data be encrypted on the local disk. Currently, the way to do this is to use the username/password entered on login to build the encryption key. Those values are always kept in memory, so it would be reasonably difficult for somebody to hack that (not impossible, but difficult).
Now the app needs to use SSO to log in. Depending on the provider, the implementations will differ, but lets say we can imagine some unique value being generated either by our server, or using the values available from the AccountManager, or something more exotic. However its done, we need a way to build the encryption key from source values that aren't kept on disk. As mentioned above, those are currently username/password, and for SSO, would be presumably something generated in another fashion.
If we were always online, we could rely on the server to keep that value in a database and return it on login. However, this app should also be able to function offline (after you've done your initial login, of course).
Any thoughts? I had explored just encrypting the whole disk, but we can't really enforce users doing that, and if there's a good chunk of data already, it'll take a long time.
Is there a way to keep these values somewhere in the OS that's not easily readable, even with root? For example, if we had a lock screen, is there some way to use the lock screen password to hold encrypted data? Its my understanding that that's the method used for the disk encryption, and there's something similar on iOS. I've read in a number of places that a 4 digit code isn't not incredibly secure, but it would be pretty good, and much better than what we have now.
Any other thoughts? I feel like I'm missing something obvious.
Thanks in advance.
Related
I'm trying understand which is the best way to store sensitive data in Android. In my app i want to insert a classic in-app-purchase model with some coins. My problem is that i'm not sure how to implement this correctly.
The initial idea was to simply use my firebase database, store the number of coins for every user and fetch the data every time the app is launched. This way I can easily detect some inappropriate usage but my users are forced to use the internet to play.
Looking at the documentations, I found this. Can this be a solution? Can I save in the internal storage the number of coins, maybe with some type of encryption, to avoid root user to modify the file? Then when the internet is on I can double-check the local stored variable with the the one in the database.
Thanks
Not an "easy" task.
Technically, you can create a SecretKey and encrypt data, so no normal user will be able to reproduce. If your concern are root users, You are kind of out of luck, as he can hook into your app while it is reading/writing that value.
But to store it online is not a solution in itself. You have to answer questions like: "Do you trust any server input"?
"How to make sure just paid coins are added"?
Have you had a look at Google Play billing?
it provides safe way's to determine if somebody paid or not.
This will require to be online.
If you have a sensitive data to save you can use sqlcipher database .. the good with it that it encrypt the database file itself so even the root user be able to get the database file he will not be able to decrypt it if you use a secured encryption algorithm.
you can find more about sqlcipher here
https://www.zetetic.net/sqlcipher/sqlcipher-for-android/
Since I assume you will grant your app a reading permission of your sensitive data and all writing processes should be reserved server-side, I would not recommend storing the data in a file on a phone, though every encryption can potentially be passed.
Maybe you already have heard about SharedPreferences, which is a good solution for let's say Preferences the user selects and that only shall affect his particular installation of your app. The difference is, that values are not stored in an external file, so not that easy accessible, BUT your app needs to write them, due only the app can access them directly (also your server can't). I am not aware of how your sensitive data is used at all but I would also not use SharedPreferences since it's injective-prone.
Official docs about SharedPreferences.
If security of your data (speaking of Confidentiality, Integrity, Authentication) is your No. 1 priority, simply don't store your sensitive data on the users device. Focus more on creating an API that ensures secure and performant passing of the relevant bits of your sensitive data. Hope this helps to give you a view of which way to go and which to walk around.
I have an integer variable in my application which I want to save for future use. Depending on it's value (like when the value is 0), I will be blocking a functionality of my app and will be requesting an in app purchase for the same.
If I save it anywhere in internal storage, it'll be flushed after Clearing Data, and if I save it in external storage, the path of the file can be easily found by decompiling the code, and server based solutions are out of my scope.
I know that a full proof security is almost impossible, and you might be thinking of downvoting my question, but I really need some advise from experts like you so that I can at least achieve maximum security, so that I can somehow figure out that the variable's value has been tampered and in that case I'll reset it to zero.
I think there is no way to secure the variable without the server implementation, so in order to achieve your functionality you can perform following steps.
First you need to check the In App Purchase product status - If it's purchased by user then you need to unlock the next functionality.
If user has not purchased or subscribe using in app purchase then you need to lock the next functionality.
In case if you want to protect stored data from reading you can use encryption to store something in the file and then use it in your application. Yes, somebody can find a path to your data, but it would be hard to read it. Also it's impossible to modify data, only corrupt.
On the other hand, it's better to use internal storage or preferences. And yes, data actually should be cleared by clearing application data. You should create default value at the start of your application, if requeired field is missing, and store it. Nothing should remains on device if user delete application\clears data.
I don't understand what the hacker can see and cannot see when he enters in a mobile app, for example android. He decompiles the .apk, then sees some .class files. If for example, I encrypt a key/value pair in a file, I still need to call this key from the code, and if the hacker can see the code, no matter if the key is encrypted, he will know which key I am calling?
My goal is to keep some encrypted string in my app, for example the twitter account Id of my app.
Some topics talk about " a private key to read, what was encrypted with a public key ", but if I use them, I still need to store them somewhere in my app...
Don't completely understand your requirement but the rule-of-thumb is always assume that client is not to be trusted.
You have to ensure that
All decryption should be done in your server (which you trust).
The client should never be able to access the decrypted data (unless you want it to). Hence whatever part of your code that needs to directly access the decrypted data should be in the server.
The client should have only the encrypted data (if it must store data).
The client should not be able to access the private key you used to encrypt the data.
If in your case your client must be able to access the critical data directly, then your only resort is to use obfuscation techniques (Basically hiding your data/code, to make it hard to find/understand). Of course all obfuscation techniques can be defeated eventually by a determined hacker. You have to decide how valuable your data is, what are the probabilities a hacker will try and access your data.
To take an extreme example : storing your twitter account and password using obfusucation is very bad. Storing a twitter-url- might not be so bad.
you can get your keys from server while launching app. and also dont manage in app purchase detail in sharedPrefrence or Sqlite. because in rooted device user can see that data file from root browser or sqlite editor application so user be able to change value.
A very determined person can crack it, but it's a major pain to crack encrypted strings and will stop most hackers. Especially if you obfuscate your code with something like ProGuard.
Answer to a similar question for details on how to encrypt
I saw similar questions but they don't fulfill my requirements.
I have an app that time to time needs to be updated from a web service. Data contains such fields as url, description, title. from 200k to 400k entries.
It is used locally and search among this data is performed quite often (depending on user's activity).
Data shouldn't be accessible by users and search needs to be as quick as possible. I know that there is no way to make it 100% unreadable, everything can be reverse-engineered and decrypted (I have to keep the encryption key on a phone). My goal is to make it as difficult as possible.
I have few choices:
1. encrypt data on server and send it as binary file to phone. Decrypt it every when needed
2. also send data as file. Read it, store to local database
3. Get it as JSON (probably encrypted), store to database or file
There is an advantage of using JSON because it will be easier to implement updates of difference between local data and remote.
Also there is a question about databases. Should I store all entries encrypted and decrypt it every time I want to find something? It might affect phone's performance.
There is also one more possible layer of protection - make encryption keys dynamic. Get a key from server once a day, re-encrypt stored data, the next day key changes. However I suppose it is an overhead. Tell me if it isn't.
What option would you choose? Are there any better solutions?
P.S. database is going to be updated daily.
Thanks
I'd store the data in SQLite, but also make the decryption scheme more intricate, using at least two keys... one, stored in the shared lib, other downloaded from the service and unlocked with that key.
This also plays into your thought up strategy - you can have one 'device' key, which comes with the APK - embedded as a hardcoded byte[] in the .SO, and another 'daily' key which will be used to open 'daily' data updates. Although, i'd rather be using the 'daily' key in a bytearray format, never saving it in any form on the device except having it decrypted in memory only for duration of it's use. This would be an upgrade to what I did, where i just saved that key as a base64-encoded devicekey-crypted string.
Working with SQLite is fairly easy, which you can see here - Android Database to Array.
I did something similar to what i'm explaining (without the updating daily keys however) here - not decrypting what I crypted.
Give it a look and discuss :)
I'm making an application where users can store data on the device. I was thinking about using database storage. But I've been reading somewhere that it is possible to manipulate data that is stored locally on the device. So what would be the best way to avoid such "attack" on the data? I have been thinking about encrypting each field in the database, but again then I have to store an encryption key on the device as well(?), which again I guess can be located? So does anyone have any other ideas/improvent of my thoughts?
Thanks for any help!
I'm looking for a way to make it a big challenge
Challenge accepted :)
The first thing you should do is to store the data in your app directory since it is not readable for the user / other apps on a regular device. Links to app data con be obtained from Context e.g. Context.html#getDir(). The directories you get from Environment are public.
That prevents average users from getting the data. But a lot of people have rooted devices and can access the data without problems, so that is still pretty insecure.
To make it a lot harder you'll need encryption. Any strong encryption that is not fundamentally broken like WEP will do. Using encryption you force the user to find the key (and encryption method) since the encrypted data can't be decrypted in reasonable time.
That leads to the problem of having a secret key somewhere available to your app but not the user. And this is the part where you need to get creative since there is no secure way to do that.
The simplest way is to put the key in plaintext in your app code. Like private static final String SECRET = "42". By simply having encrypted files you will already stop most users from digging further since at that point you need some programming skills to read the data.
If the user has those skills he will likely start to look at the code of your app (using e.g. dex2jar + jd-gui). You should do the same if you want to know how hard it is to reverse engineer your app.
Understanding the code / finding the encryption method + password will get harder if you use proguard to obfuscate the code because app internal class-, method- and variable names will be shortened to A.B.c(d) like code. But method calls to Android's API can't be renamed since you would need to rename the methods on the device. Also string constants like "42" won't be changed.
The next step of making it harder is to replace that constant by something dynamically generated by your code. The basic example below for example builds the password by dividing numbers by two. The advantage when using this approach is that the password is no longer stored in plaintext and you need to understand / reverse engineer the method that converts the data into the password.
private static final byte[] password = {8, 4};
private String getPassword(byte[] data) {
StringBuilder sb = new StringBuilder();
for (byte b : data) {
sb.append(String.valueof(b / 2));
}
return sb.toString();
}
// returns "42" if I did not make a mistake
The next vulnerable point is that calls to device crypto APIs can be easily located (since they can't be renamed) which makes it a lot easier to figure out where to look for the encryption. If you don't want to write your own crypto method which I would strongly suggest you don't because a slight error in here may corrupt data or break the complete encryption.
That problem can be hardened if you use reflection for example (calling methods by supplying the name of the method / class supplied in a String). That String can as well be obfuscated like above example did with the password.
If you do all that and don't use a method not as simple as this one you can make it really hard. dexguard for example can do that for you but it's not free and has the problem that the same method is used for many apps and a lot more people will try to break that than your custom method.
Finding a good method to hide information in your app that is used to generate a key and a method to hide the key generation & encryption / decryption is best figured out by yourself so the method itself is not public knowledge.
You can use combine a lot of techniques to hide the information like moving parts of that into native code so Java guys like me have a hard time or use a network connection to let your server do some work.
But in the end it's all Security through obscurity and all the extra security measures don't benefit the user but require extra processing time & additional app size.
So what would be the best way to avoid such "attack" on the data?
Do not put it on the device.
I want to make the data secure against the user of the app.
Then do not put it on the device. It is the user's device and the user's bandwidth, and hence it is the user's data.
But I'm looking for a way to make it a big challenge if the user finds out he/she will try to do so.
Simply using a database or something else on internal storage will stop 99% of Android device users from accessing your data. There is nothing you can do to stop the remaining 1%.