Shouldn't Android AccountManager Store OAuth Tokens on a Per-App/UID Basis?

前端 未结 4 806
既然无缘
既然无缘 2021-01-29 19:18

Android\'s AccountManager appears to fetch the same cached auth token for apps with different UIDs - is this secure? It does not seem compatible with OAuth2, since access tokens

4条回答
  •  醉酒成梦
    2021-01-29 20:24

    I reckon @Michael answered the question perfectly; however, to make the answer more sensible and short to those looking for a quick answer I am writing this.

    Your concern about the security of android AccountManager is correct, but this is what OAuth is meant to be, upon which android AccountManager relies.

    In other words, if you are looking for a very secure authentication mechanism this would not be a good option for you. You should not rely on any cached tokens for authentication, since they can be easily revealed to the intruder in case there is any security vulnerability on the user's device such as inadvertently granting access permission to the intruder, running a rooted device, etc.

    The better alternative to OAuth in more secure authentication systems, e.g. online banking apps, is using asymmetric encryption using public and private keys, in which the user is required to enter their password every time for using the services. The password is then encrypted using the public key on the device and sent to the server. Here, even if the intruder gets known of the encrypted password, he cannot do anything with that because he cannot decrypt it with that public key and needs only the private key of the server.

    Anyway, if one wants to make use of the AccountManager system of the android as well as maintain high level of security, it would be possible by not saving any tokens on the device. The getAuthToken method from AbstractAccountAuthenticator can then be overriden like this:

    @Override
    public Bundle getAuthToken(AccountAuthenticatorResponse response, Account account, String
            authTokenType, Bundle options) throws NetworkErrorException {
        AuthenticatorManager authenticatorManager = AuthenticatorManager.authenticatorManager;
        Bundle result;
        AccountManager accountManager = AccountManager.get(context);
        // case 1: access token is available
        result = authenticatorManager.getAccessTokenFromCache(account, authTokenType,
                accountManager);
        if (result != null) {
            return result;
        }
        final String refreshToken = accountManager.getPassword(account);
        // case 2: access token is not available but refresh token is
        if (refreshToken != null) {
            result = authenticatorManager.makeResultBundle(account, refreshToken, null);
            return result;
        }
        // case 3: neither tokens is available but the account exists
        if (isAccountAvailable(account, accountManager)) {
            result = authenticatorManager.makeResultBundle(account, null, null);
            return result;
        }
        // case 4: account does not exist
        return new Bundle();
    }
    

    In this method, neither case 1, case 2 nor case 4 holds true because there is no saved token, even though the account is there. Therefore, only case 3 will be returned which can then be set in the relevant callback to open an Activity in which the user enters username and password for authentication.

    I am not sure of being on the right track in further describing this here, but my website posts on AccountManager may help just in case.

提交回复
热议问题