What protects Android AccountManager passwords from being read by other apps? - android

I'm writing 1) an app that stores a username and password in the AccountManager, and 2) a separate background Service app that accesses those credentials to login to my servers, etc. Playing around with this, I find I'm able to call AccountManager.getPassword(account) from the Service (app 2) to access the type of accounts I've add to the AccountManager using the other app (app 1).
Due to this, I'm starting to wonder what stops an arbitrary malicious app from 1) including the fields in the manifest to have Account management access, and then then 2) from iterating through all accounts of a particular type and calling mAccountManger.getPassword(account) on them. I know that during installation, a dialog pops up with all the permissions that an app requests to use, but I don't think we can count on the average user to reject an app because it requests suspicious permissions.
Is there a way to prevent getPassword from being called on an account type? Are there ways to protect accounts in the AccountManager from apps that have given themselves lots of account permissions?

Account data protection is based on the Linux user id (UID) of the process making the request. (See Security and Permissions in the guide.) Each account is associated with an account authenticator (that has a UID), and the process calling getPassword (or several other methods) must have the same UID as the authenticator.

Related

How to get the user id (or unique token) to make sure the app was bought in the app store

My system consists of a mobile app (a Cordova app), and a webservice, providing all the relevant data. When a user buys the app in the appstore (or playstore, if android), a user account should be created on the webservice, ideally without any user interaction (no registration). The user account could be linked with the gmail account, apple id, ... This is required, to only allow people who have paid to use the webservice.
My Problems:
I did not find a way to get the user id of the user. (Android seems to have a way: https://github.com/loicknuchel/cordova-device-accounts , but iOS not).
I only want exactly one registration per user. This saves me from using something like a registration page, when the app is first started - this could easily be bypassed and lead to multiple registrations.
The user account should be linked to the user and not the device (so no device UUID or so, as this would not be portable between devices).
Ideas that I had:
(Favorite, doesn't seem to be possible) I have a method "getUserID()" in the app, which returns the right user on the phone. Additionally, I have access to an API to check who bought my App. I can easily cross check, to make sure that the user has permission to use the webservice.
(Unnecessary complicated, seems wrong) Make the app free, use a single in-app purchase to buy access to the webservice. When I searched, I found that it seems that in app purchases give you more information, so there might be the chance to link the app with a user.
(Even worse than 2.) Make the app free, use an own payment system/registration.
My question:
What does the Android/iOS app-store eco system provide, so that I can ensure that one user buying the app creates exactly one user account on my webservice, and this user account is linked to the user and not the device?
You should generate a secret api key for each paying user.
Then the user should use this key to auth into your API and get a token back (you can make it expire after some time if you want a stronger protection). User should attach this token to all of his api calls.

how to force the user to sign in every time?

Im developing an android application for the first time (no prior experience whit coding....). Mainly the app is going to be used at work as a tool for service technicians. The app is almost ready for field testing, but there is one thing i need the app to do before that. I need the app to force the user to log in every time its opened. This is because some of the info on the app is confidential, and only people that currently works for the company is allowed to have this info. Whit firebase i can then block the users that leave the company, or users that are not verified. Currently the users sign in whit google and they stay signed in until they clear the app data or delete it.
I have looked far and wide for the answer to this, but i have only come across different use of timers.
If anyone has a better solution to this "safety" issue, im open to anything.
If you are using Google Sign-In for authentication, there is no out of the box support for forcing your user to authenticate with Google every time they use your app.
This makes sense, because the user is still authed with Google on your phone. A login system only authenticates the user; it doesn't inherently protect data stored on the device. As long as Google has a valid access token, the user won't have to type a username and password again (and simply clicking "login with Google" again doesn't really provide extra protection here).
If your primary concern is blocking access to users who have left the company, you should be covered if you are using Google Apps for your company. If you disable the user's account, their access tokens should become invalid. Google Apps admins can also manually revoke access to specific apps for specific users.
If you don't use Google Apps (e.g. your users are using #gmail.com accounts or accounts from a domain outside fo your control), you might want to consider implementing a list of users allowed to access the application, and verify the current user has access by checking that list via an API call on launch.
If the goal is really protecting the confidential information in the application, you might want to take an approach similar to Android Pay in which you require your user to set and enter a PIN number to access the application. As an added benefit, you can then use that PIN to encrypt any confidential data you are storing locally.
I will suggest you take a look into shared preferences and every time when the user is back into the app you send them to the login activity.

Android - How to protect or delete an account when application is uninstalled?

Following Udinic's blog shows us how to create our own authenticator and manage our own accounts.
The problem is that if two applications try to manage the same account type, only the account authenticator of the first application will be used (and only the first application can access certain methods of the AccountManager).
However, if the first application is uninstalled, then the second application's account authenticator takes its place and the second application has full access to the account.
How can I prevent that - given my application gets uninstalled - no other malicious (already installed) app can 'take over' the accounts created by my application and thus read out my user's passwords or other private data?
I checked apps like facebook or viber, they seem to automatically remove the account if the app is uninstalled. How can they do that?
(Please don't respond with 'you should not store the password' - That is not the question here)

Check if a device google account is authenticated, only then allow access to my offline app

I have a private app which works totally offline (i.e. no server data sent/recieved), however I have a need to restrict it only to users with a valid Google account on their phone. I can get make sure there is a suitable account on the phone by iterating a list of phone accounts, but is it possible to check the account is valid/authenticated without me having to introduce the full OAuth process? I have no need to get a cookie or send any data to a server.
Ideally I'd like to do something like:
1. Check with the account manager for an auth token.
2. If token recieved then allow access to the app.
Currently without any checks via the account manager, anyone could create a fake account on the phone and then gain access even if they put in a email/password and they would never be authorised.
I hope I've explained this clearly. As my app has no network connectivity so I would like to avoid adding any of my own network/oauth checking.
What about this:
AccountManager manager = AccountManager.get(this);
Account[] accounts = manager.getAccountsByType("com.google");
final boolean connected = accounts != null && accounts.length > 0;
The connected boolean will indicate if there is a connected Google account in the phone.
Indeed there won't be any check on the token, but if the account is registered on the phone, then Google checked it before, server-side, to validate it...
How about implementing Google Plus login API? It's not really setting up a full OAuth process since G+ it's fairly simpler, even if it is actually built on top of OAuth.
I use that in an app I'm developing that also does not require online access (except for initial G+ login access).
What I do is the first time the app is run I present the G+ login button. After user clicks on it he can accept the permissions request from my app (to be able to retrieve user email and some basic profile info, i.e. minimum permission needed) and if the API client connects correctly then I present the user with the dashboard or home screen and also set up a flag in SharedPreferences about the user being already authorized.
In this way, the next time the user starts the app it will remember it was already authorized and just ask the API client to connect (only if the access was revoked from the account's Play Store website do we need to re-verify that the user auth is still valid), and everything should work. If the user revokes the access to his G+ profile from my app, I clear the flag so the next time the user runs it it asks for authorization again.
It's actually very simple and at least for my use case (Which sounds very similar to yours) it works for what I want it with minimum user intrusion.
I strongly suggest you try out something like this Google Plus login tutorial
Edit: You can also check this question I asked before, about working with multiple activities that need Google Plus functionality
Also, forgot to say that with this method you are always sure that the user account is always valid since you are checking directly with Google's servers about its validity.

Google Play Services - Clear allowed accounts

When using the new Google Play Services to authenticate an account, you first use the AccountPicker to allow the user to select an account. If the user has not authenticated with your application before, a UserRecoverableAuthException will be thrown which gives you an intent to show the 'Allow Access' page. You only need to allow access one time. However, for testing purposes, I need to be see the Allow Access page every time.
So, does any know how you can clear the permissions for Google Play Services? Or some other method that will show the allow access page every time?
In your Google Account Settings, there's a way to set up application-specific passwords. Sign up for 2-step verification and then you can create them. To temporarily revoke the permission, you can remove or change the password: http://support.google.com/accounts/bin/answer.py?hl=en&answer=1070455
Otherwise, change the password to your entire Google account temporarily.
Unfortunately I don't think there's an easy programmatic way to do this. It seems like quite a serious security flaw that a user/administrator can't revoke Google Account access to an installed app. From what I can tell, Google is fetching the authentication information from a server, and if something in that operation fails, it throws the UserRecoverableAuthException. That's when you normally fire off the Intent from UserException.getIntent(), which contacts the server with a request such as:
scope:oauth2:https://www.googleapis.com/auth/drive.readonly[
account:<your_account>#gmail.com,
scope:oauth2:https://www.googleapis.com/auth/drive.readonly,
extrashash:<some_number>]
Now there's no documentation I've found for instructing the server to revoke that Auth Scope requested above. It might not even be possible. However, you could try to capture the values in the Intent returned by UserException.getIntent() and use it to create a new Intent you launch whenever the user wishes to sign in with their Google account. However, the server might realize the app is already authenticated, and then send you through without the prompt.

Categories

Resources