4

I am currently building an app for Android that requests data from my backend server. Of course, I want to know if a request received on my server really comes from my app or if someone just sends HTTP requests from another server etc. I read Tim Bray's article on that topic, but want to know how secure this approach really is. The article mentions that a rooted device might be able to compromise security, but I was thinking about the following scenario:

  • A malicious person takes my app, fully decompiles it and detects that I use GoogleAuthUtils
  • She/he changes my app in order to hack it and deploys it onto her/his device (using the same package name etc.)

I know that the fake app's signature will be different (since the malicious person does not have my private key) and that it cannot be downloaded from the Play Store (because no two apps with the same package names can be published there).

Provided the device is not rooted: is this fake app getting the same (or any) result from GoogleAuthUtils.getToken() as my real app?

What are the possible changes that the hacker could apply to the response on a rooted device (I could also ask: which fields of the response are signed by Google so I could detect whether they are untampered)?

Mangesh
  • 5,491
  • 5
  • 48
  • 71
svenpanko
  • 180
  • 8

1 Answers1

1

i have not testet that... but i would say that getToken would not get any result because of the wrong signature...

you cannot create a oauth client in the google developer console without the fingerprint of the certificate used to sign the app in combination with the package.

thats why i would say that getToken does not receive any critical if the malicious person does not have your release keystore and private key

edit: PS: i know... this answers only one of your questions...

edit2: i have tested it out and could get a valid token with a wrong signature. if a changed the signature i got the following exception:

03-17 18:08:05.195 3315-3498/org.example.myapp E/GoogleOAuthTask: Error getting token
com.google.android.gms.auth.UserRecoverableAuthException: NeedPermission
    at com.google.android.gms.auth.GoogleAuthUtil$1.zzam(Unknown Source)
    at com.google.android.gms.auth.GoogleAuthUtil$1.zzan(Unknown Source)
    at com.google.android.gms.auth.GoogleAuthUtil.zza(Unknown Source)
    at com.google.android.gms.auth.GoogleAuthUtil.zza(Unknown Source)
    at com.google.android.gms.auth.GoogleAuthUtil.getToken(Unknown Source)
    at com.google.android.gms.auth.GoogleAuthUtil.getToken(Unknown Source)
    at com.google.android.gms.auth.GoogleAuthUtil.getToken(Unknown Source)
    at org.example.myapp.shared.security.authentication.google.GoogleOAuthTask.doInBackground(GoogleOAuthTask.java:39)
    at org.example.myapp.shared.security.authentication.google.GoogleOAuthTask.doInBackground(GoogleOAuthTask.java:20)
    at android.os.AsyncTask$2.call(AsyncTask.java:288)
    at java.util.concurrent.FutureTask.run(FutureTask.java:237)
    at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:231)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
    at java.lang.Thread.run(Thread.java:841)

Then i made something like this to get the permission dialog:

try {
    token = GoogleAuthUtil.getToken(context, emails[0], "oauth2:profile email");
    GoogleAuthUtil.clearToken(context, token);
} catch (final UserRecoverableAuthException e) {
    final Intent intent = e.getIntent();
    context.startActivityForResult(intent, MyApplicationRequestCodes.SECURITY_OAUTH_PERMISSION);
} catch (final GoogleAuthException e) {
    Log.e(LOG_TAG, "Error getting token", e);
} catch (final IOException e) {
    Log.e(LOG_TAG, "Error getting token", e);
}

after the dialog when it returns in the activity i made this:

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    Log.d(LOG_TAG, "returning from an activity. (requestCode=" + requestCode + ", resultCode=" + resultCode + ", data=" + data.toString() + ")");

    if(requestCode == SECURITY_OAUTH_PERMISSION && resultCode == RESULT_OK) {
        login();
    }

    if(requestCode == SECURITY_OAUTH_PERMISSION && resultCode == RESULT_CANCELED) {
        authenticationHandler.onUserCanceled(new AuthenticationError(
                AuthenticationErrorEnum.USER_ERROR,
                "User closed permission dialog."
        ));
    }

the login() then starts the same procedure again, and then i received a VALID token and i could authenticate agains another API secured by google token. in my example it was a firebase DB.

From firebase i got the Authentication result (the ):

AuthData{uid='google:123412341234333', provider='google', token='***', expires='1458340206', auth='{uid=google: 123412341234333, provider=google}', providerData='{id=987234987032972034097234, accessToken=I_REMOVED_THE_TOKEN_STRING, displayName=Stefan Heimberg, email=kontakt@stefanheimberg.ch, cachedUserProfile={id= 987234987032972034097234, email=kontakt@stefanheimberg.ch, verified_email=true, name=Stefan Heimberg, given_name=Stefan, family_name=Heimberg, picture=https://lh4.googleusercontent.com/--XEA5G7LkjI/AAAAAAAAAAI/AAAAAAAAAAs/dpvdzBNpd6U/photo.jpg, locale=de}, profileImageURL=https://lh4.googleusercontent.com/--XEA5G7LkjI/AAAAAAAAAAI/AAAAAAAAAAs/dpvdzBNpd6U/photo.jpg}'}

So, finally i Must say that it is possible to get a valid token even when the signature is not the same as configured in google console.

But after i change the signature then my application must handle the com.google.android.gms.auth.UserRecoverableAuthException and restarts the whole login procedure.

StefanHeimberg
  • 1,455
  • 13
  • 22
  • this is exactly what I am not sure and would like to have a "definitive" answer. Anyone who decompiles my app sees the Webapp Client ID (not the App Client ID from the console) I am providing to the method call, so faking that is not a big deal. But the question is more: is this app able to send a request towards Google to get a token when the app's signature is not correct? – svenpanko Mar 16 '16 at 13:12