Security with SharedPreferences
If you are interested in state of the art implementation, check out my project here https://github.com/patrickfav/armadillo which may have some interesseting design principles relevant to this discussion.
Discussion 1: The Attacker is Another App
There are different points to consider:
Shared Preference on an unrooted Device
The data is safe here on the code level. It can only be accessed through the app (in malice or normal manner)
Encrypted Shared Preference on a unrooted Device
Same as above. Your data is safe. No difference in security level, it's just as safe or unsafe as it would be unencrypted (but slightly obfuscated).
Shared Preference on a rooted Device
The data can be accessed and manipulated by any App. But you have to consider that only a very small percentage (I guess under 1-2%, but there is no reliable data on the interweb) of devices are rooted and if a user roots his device he/she deliberately leaves himself vulnerable. This is not an Android system setting, if you root, you are responsible for the consequences.
Encrypted Shared Preference on a rooted Device
So you have the option to encrypt your data. There a ready solutions for this. But the problem is to keep the key secret. A hardcoded key in source code can easily be decompiled (even with byte code obfuscator like ProGuard). A per-app generated key has to be saved somewhere, and in the end on a rooted device, it can be accessed irrelevant of the location (shared pref, SQL, file). A server side per user key that is only saved in RAM is a little more secure, but degrades usability as you need to make a server request the first time the app is started or every time it's garbage collected. This may interfere with offline capability.
Aside from the last method, encrypting your shared preference hardly gives any real security enhancements.
Implication of developing a malicious app
Since April '14 Google has a malware scanner embedded in the play services on the device (also in the play store server side) that detects malice apps and its definition is frequently updated (at least every 6 weeks as is the release cycle of the play store app) and works with every Google Android 2.3+.
As a potential developer of a malicious app that reads your data I have to consider that my app only works on a small percentage of devices and then also only a brief period and my main distribution channel would be to make people download the APK and manually install the app and hopefully won't be recognized by the malware scanner immediately, which combined is a very unlikely scenario. This would make me inclined to use other means of intrusion which have a better effort-to-return ratio.
I guess that's the reason there are still only a few malice apps for Android and no widespread "infection" at least I know of (middle 2015).
Should an App store sensitive data?
I would rethink if your design fits your requirements. Usually you want to store the least sensitive data you can and only get it from the server if you need it and then only keep it in RAM as long as you need it. Data that is potentially very damaging therefore should not be saved persistently on the device (if possible). As we discussed data on your Android phone cannot be secured in a way that satisfies every security requirement.
Aside from that, you also have to consider to secure the data on the UI level or otherwise anybody could just take your phone and access the nuclear bomb codes through the app.
tl;dr
- Persist only the sensitive data on your phone that you essentially need to keep a reasonable usability of your app. Everything else belongs in the RAM (as e.g. a object member) and should be fetched on demand and kept as brief as possible
- The existence of an effective malware for your app is unlikely
- Shared Preference is safe on all devices that are not deliberately made vulnerable. You have no influence on that so you cannot be held responsible as it is not a standard feature of the phone
- Encrypting your data on a android phone hardly gives any real security enhancements
Discussion 2: The Attacker is the Device Owner
Protecting dynamic App configuration - or how to protect yourself from the device owner
There might be an additional use case where manually encrypting data makes a lot of sense: If you want to make it harder to read and alter your app's internal configuration. A simple example would be: you have a boolean flag, when a user e.g. "likes" your FB page, will disable ads. If you just store a true
or false
it is trivial for the device owner to change that. For this scenario a good "obfuscation" might be enough for most attackers. Be aware that your encryption scheme must be authenticated meaning it should not only encrypt but leave a tag to check if the data has been modified. It would also be best to make it non-deterministic and device depended because otherwise an attacker could just copy the value from another device. For sample implementation of this approach see here.
Ways of improving protection against device owner
- See whitebox crypto for a solution on how to encrypt data on vulnerable devices.
- Android Keystore System
The 2017 Update with Android 5/6 and the Area of the Android Keystore System
Inofficially released with Android 4.3, with it's first public release with Android 5 and vastly improved API and capabilities with Android 6, the Android Keystore System made it possible to encrypt data and store keys with the device's secure hardware platform. On the face, this makes for a very strong concept which makes it impossible even for attackers with the device in hand to decrypt your data. In it's strongest configuration the Android Keystore System only decrypts, if the user either unlocked the screen or provided his fingerprint. This is not only more user friendly by not introducing additional passwords, but also does exactly what you want: The data is encrypted if the phone is locked (not only if it is off) und decrypted when the user unlocks her phone.
Unfortunately this concept has a major flaw: it is very unreliable. You are at the mercy of device fragmentation with major manufacturer providing unstable and non API confirm implementations. Drivers and/or SoC themselves often have major bugs and behavior might not what you want (e.g. by deleting your keys when the user changes or deletes their lock screen). Even different Android versions behave differently. These observations were made by me during a project with very high requirements for persisting sensitive data during the time of 2017-2018 (lets say I added couple of Android Bug Tickets - which all got ignored of course). It is possible that newer devices and Android implementations are better now, but until I see otherwise I would be aware.
SharedPreferences
are eventually stored on an XML file in the application folder under /data/data/... - this path should be private and is not accessible on an un-rooted Android device running stock firmware, either by another application or by the user directly. It is however possible to root the device and then simply access this folder with UID 0, or even change the permissions.
So to your question:
So is there any method to protect my SharedPreferences from being accessed from anywhere
From the application's point of view it is not possible to modify how your application's private files are stored or protect them in any way as this is a filesystem setting and handled by the OS.
Or better still if some one can advise safer data storage option
The only solution at hand is to encrypt the data prior to storing it, whether it be using SharedPreferences
or even using a local SQLite database. You might also consider using this library which provides transparent, 256-bit AES encryption of SQLite database files.
Also bear in mind that your APK can be decompiled, so be mindful about encryption keys in your code.
One final note - The Android emulator acts as a rooted device by default, so if you want to peek around using ADB without having to root your device, you could definitely do that quite easily.
Cheers.