I'm creating a app to store encrypted data.
In this question, the OP si advised to store user's credential in clear.
But what if I'd like to store an encrypted password created with SecretKeySpec (the one used to encrypt data)? From my understanding the secret key is itself encrypted.
So I can I store and retrieve it.
Note: I'm not asking how to store preferences, just if my understanding of how SecretKeySpec works and how to, sort of, serialize and retrieve the encrypted password.
EDIT: Sorry, I forgot to specify it needs to be compatible with API level 4.
Straight from the developer website.
Be Smart About Security!
It's important to understand that AccountManager is not an encryption service or a keychain. It stores account credentials just as you pass them, in plain text. On most devices, this isn't a particular concern, because it stores them in a database that is only accessible to root. But on a rooted device, the credentials would be readable by anyone with adb access to the device.
With this in mind, you shouldn't pass the user's actual password to AccountManager.addAccountExplicitly(). Instead, you should store a cryptographically secure token that would be of limited use to an attacker. If your user credentials are protecting something valuable, you should carefully consider doing something similar.
Remember: When it comes to security code, follow the "Mythbusters" rule: don't try this at home! Consult a security professional before implementing any custom account code.
Now that the security disclaimers are out of the way, it's time to get back to work. You've already implemented the meat of your custom account code; what's left is plumbing.
Wow. I really don't think storing the user's password in the clear is a serious option.
Check out AccountManager which was designed for this purpose. Although it got downvoted in the question you linked to, SampleSyncAdapter really is a good resource for an AccountManager example, and the only one I know of included with the SDK.
Edit - about javax.crypto, I think it is a lower-level API than AccountManager. From the docs:
Many servers support some notion of an
authentication token, which can be
used to authenticate a request to the
server without sending the user's
actual password. (Auth tokens are
normally created with a separate
request which does include the user's
credentials.) AccountManager can
generate auth tokens for applications,
so the application doesn't need to
handle passwords directly. Auth tokens
are normally reusable and cached by
AccountManager, but must be refreshed
periodically. It's the responsibility
of applications to invalidate auth
tokens when they stop working so the
AccountManager knows it needs to
regenerate them.
I'd hate to deal with this on the level of javax.crypto if I didn't have to.
u can simply declare both username and password as an if statement if condition matches u can start the activity in case of wrong u can simply generate a toast of wrong input.but u can not retreive password from there if u lost by any mean but yess u can create many passwords for a single user.i added this thing to my application and working well for me.
Related
I'm trying to work out the best solution for a particular situation I'm in, and am having trouble working out the best option. It's a tricky setup, so might be a fun challenge for you Android experts! Here's my situation:
We have two Android apps already on the Play Store, and are working on another right now.
The two released apps are signed with the same keystore, but do not currently have a sharedUserId set in their manifest files.
The two released apps store a user's oAuth token in SharedPrefs, some product/content data in an SQLite DB, and some audio/video content in external storage (using getExternalFilesDir).
The apps are all separate oAuth clients/applications of our server (i.e. they all use different client ID and secret keys).
Our server is setup to only allow one oAuth token per oAuth application (i.e. Android app). e.g. if a user logs in to app A on one device, then logs into app A on another device, the first device's token will be invalidated and the app will receive a 401.
We've successfully implemented a single sign-on system on iOS by enabling shared keychain between the apps. If an app detects that another app in the group has a valid oAuth token, it can send that to our server and exchange it for a valid token for that app.
In the iOS version, we wanted to ensure that the apps didn't need to know about the existence of the other apps using hardcoded values per-app (e.g. if we release a new app in the future, other apps don't need to be updated to share/receive tokens with it), so we created an entry in the keychain containing an array of bundle IDs that had valid tokens, that all apps could access. When an app successfully logs in or exchanges a token, they add their own bundle ID to that array. Any newly installed app could find a bundle ID from that array, and use that it as a key for loading the token details for that app, which it would then exchange for its own fresh token.
We want the token exchange to be automatic and not require input from the user.
I hope that all makes sense!!! Please let me know if not.
I'm now trying to work out the best method for storing oAuth tokens (plus some additional data such as email address to go with it) on Android so that other apps owned by our account can access them in order to exchange for a fresh token.
I've looked into using the following, but am unsure of the best route:
SharedPreferences along with sharedUserId
AccountManager (https://developer.android.com/reference/android/accounts/AccountManager.html)
Android Keychain (https://developer.android.com/reference/android/security/KeyChain.html)
ContentProviders
The problem with option 1. seems to be that setting the sharedUserId after first release will lose access to all of the data (see http://java-hamster.blogspot.jp/2010/05/androids-shareduserid.html). This is not a nice thing for our users.
Option 2. (AccountManager) could be a good option, but if we want to store the tokens separately (per-app), but want any other apps we make to access their tokens, I'm not sure how we'd do that.
Option 3... is it possible to do what we need with Keychain?
If I understand correctly, option 4 would need each app to have its own ContentProvider? I'm not sure how that would work for our requirements.
If anyone has gone through this kind of situation and could share some insights and recommendations, I'd really appreciate it!
ContentProvider is probably your best best. I won't be able to provide the whole code for you to do this, but this is generally how I see it working:
Each app creates a content provider that exposes their own API token;
Each app tries to acquire and query (sequentially until successful) all the other content providers before requesting a login;
If app X is able to acquire and retrieve the token from app Y (via Y's content provider), then store it in app X and use it;
Side notes:
This is very sensitive information, so you should enforce security. Your content providers should only be accessed by other apps signed with the same key, they should have only read permissions and you should create your own custom permission as well.
The content provider does not need to access an sqlite database. It can access whatever your using to store the token (which I hope is stored in a secure way, but I'll leave that to your own judgment)
Useful links:
How to create a custom content provider
How to secure your content provider
Example of content provider that retrieves data from shared preferences;
AccountManager is meant to solve the exact problem that your are commenting. Here is a good tutorial to work with it:
http://blog.udinic.com/2013/04/24/write-your-own-android-authenticator/
Just be sure that you sign all your apps with the same keystore, because this is the only thing that might complicate things (a lot).
Using preferences will lead you into a problem as all that you store in the main thread is not guaranteed to be there in a Service (like a SyncAdapter). There used to be a trick for this in the form of flag (MULTI_SERVICE) but was deprecated in api 23.
ContentProvider is of course possible (its too generic) but AccountManager will help you to cover the corner cases related from refreshing tokens and other interesting stuff.
I need to store user credentials in my Android app. The application sends HTTP requests to a server and the credentials are used to authenticate with that server.
I know that many articles and many discussions about this topic already exist. However, I would like to ask for help considering the following specific requirements:
The user should be asked to type username and password just once. After that, the application must be able to authenticate with the server forever.
If the server receives an authentication request that contains username and password, it generates a random token and sends it back to the client.
The client must add the token to other requests (as an HTTP header).
The validity of the token always expires an hour after it was generated. The client must send another authentication request with username and password to get a new token.
Note that the server provides a custom authentication mechanism that does not follow any standard.
I would say that these are very strong requirements and that they already impact some security issues. However, let's suppose that these conditions cannot be changed and that they must be met by the Android app.
Here is what I am going to do:
As the user should provide credentials just once per app installation and as the token on the server side has a limited validity and the client must re-authenticate with the credentials again and again, the Android app cannot avoid storing the password.
I will store the credentials into DB (by subclassing SQLiteOpenHelper from the android.database.sqlite package).
I will encrypt the credentials before storing them but the key used for encryption/decryption will be just a constant hardcoded in the app.
Additionally I will set android:allowBackup to false in the manifest file and obfuscate the application.
I know that an attacker with physical access to the device can get the credentials. I am also aware that some of the suggested steps are just little obstacles for such attacker.
However, is there something more I can do to improve security if there are the requirements mentioned at the beginning of the question?
Thanks.
If I were in your shoes, I would use SQLCipher to store the user credentials. This is a simple way to create and use an encrypted (using AES) sqlite database with minimal hassle.
Of course, this doesn't solve the whole problem. You still need a secure way of generating/storing the key to said database. If I were to recommend any option, I would advise requiring users to input a password/PIN whenever they open the app, and use said password/PIN as the database key.
An alternate method would be to generate a unique, random key upon app installation, and store it in the Android Keystore. A truly dedicated/well-funded attacker would still be able to retrieve the key, but only for the database on that one device.
My web API requires an authentication token to access protected resources. I can request and receive these, and consume the api. Now I want to store this token for later usage.
I am aware that it is hard or even impossible to securely store confidential data, but this article suggest to use the KeyStore to store tokens, which might be the best way to go. I read somewhere that the stock email app also uses this approach, but unfortunately I cannot remember the source.
I would like to use the KeyStore in combination with the AccountManager, so the user can view and manage all registered accounts (tokens) on their device.
Is this possible? If so, how can I achieve this? I can't seem to find a way to 'attach' a reference to a keystore entry to an account.
Any suggestions or alternatives are welcome as well! Thanks in advance!
So, if you encrypt/decrypt something into/from keystore you are using an alias. For example, your account name. Or you can store aliases in AccountManager.
You can decide if it is better to use account name as alias in keystore (remember that you should provide ability to create an account from settings). Or you want to randomly generate aliases and store them in AccountManager as additional data (UserData). Keystore part is very nicely documented, the account manager is not. I remember that research on that took me some time and implementation slightly differs based on application type.
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
If I want to store the username and password to be used inside an Android application, what is the best way to do it? Is it through the preferences screen (but what if the user misses this?), or pop up a dialog box and ask the user for the credentials? If so, I do have to maintain state for the application. How would I do this?
Most Android and iPhone apps I have seen use an initial screen or dialog box to ask for credentials. I think it is cumbersome for the user to have to re-enter their name/password often, so storing that info makes sense from a usability perspective.
The advice from the (Android dev guide) is:
In general, we recommend minimizing the frequency of asking for user
credentials -- to make phishing attacks more conspicuous, and less
likely to be successful. Instead use an authorization token and
refresh it.
Where possible, username and password should not be stored on the
device. Instead, perform initial authentication using the username and
password supplied by the user, and then use a short-lived,
service-specific authorization token.
Using the AccountManger is the best option for storing credentials. The SampleSyncAdapter provides an example of how to use it.
If this is not an option to you for some reason, you can fall back to persisting credentials using the Preferences mechanism. Other applications won't be able to access your preferences, so the user's information is not easily exposed.
You should use the Android AccountManager. It's purpose-built for this scenario. It's a little bit cumbersome but one of the things it does is invalidate the local credentials if the SIM card changes, so if somebody swipes your phone and throws a new SIM in it, your credentials won't be compromised.
This also gives the user a quick and easy way to access (and potentially delete) the stored credentials for any account they have on the device, all from one place.
SampleSyncAdapter (like #Miguel mentioned) is an example that makes use of stored account credentials.
I think the best way to secure your credential is to first think of storing the Password with encryption in the account.db file which couldn't be easily available in non rooted devices and in case of rooted device the hacker must need the key to decrypt it.
Other option is do all your authentication like the way Gmail is doing. after the first authentication with the Gmail server . you got the Auth Token that would be use in case of your password . that token would be store in plain text.this token could be false in case you change the password from Server.
the last option I'd recommend you to enable 2-Factor Authentication & create Device Specific Password for your device. After losing device, all you need is to disable that device.
Take a look at What is the most appropriate way to store user settings in Android application if you're concerned about storing passwords as clear text in SharedPreferences.
You can also look at the SampleSyncAdapter sample from the SDK. It may help you.
Take a look at this this post from android-developers, that might help increasing the security on the stored data in your Android app.
Using Cryptography to Store Credentials Safely
With the new (Android 6.0) fingerprint hardware and API you can do it as in this github sample application.
These are ranked in order of difficulty to break your hidden info.
Store in cleartext
Store encrypted using a symmetric key
Using the Android Keystore
Store encrypted using asymmetric keys
source: Where is the best place to store a password in your Android app
The Keystore itself is encrypted using the user’s own lockscreen pin/password, hence, when the device screen is locked the Keystore is unavailable. Keep this in mind if you have a background service that could need to access your application secrets.
source: Simple use the Android Keystore to store passwords and other sensitive information
The info at http://nelenkov.blogspot.com/2012/05/storing-application-secrets-in-androids.html is a fairly pragmatic, but "uses-hidden-android-apis" based approach. It's something to consider when you really can't get around storing credentials/passwords locally on the device.
I've also created a cleaned up gist of that idea at https://gist.github.com/kbsriram/5503519 which might be helpful.