How does facebook verify app authenticity with key hash?

When developing an android app with facebook, you are required to upload the key hash of your app to their site. With this they claim that they are able to verify that the calls to their servers are actually made from your app.

I've read this question How does Facebook verifies mobile apps but it doesn't really provide the actual implentation of this. I've tried looking into the source code of the facebook library but couldn't figure it out.

Which data is sent out of the android app and under what encryption that can be verified against this hash in the server? Is the method implemented by facebook fail safe?

If it is, and the it can be implemented in any server I could use it to verify against my server that my apps haven't been recompiled with different code (Which tends to happen pretty often :( )


I'm currently implementing this idea in this way:

Signature[] sigs = context.getPackageManager().getPackageInfo(context.getPackageName(),     PackageManager.GET_SIGNATURES).signatures;
for (Signature sig : sigs) {
    verifyInServer(sig.hashCode());
}

Where verifyInServer is pseudocode for the check made against the server with the stored value of the signatures. It has worked for now but I'm not sure that it's safe, and I'd rather check against a key hash (that its public) than this signature data (that I'm not really sure if it's private and not spoofable by the user).

Answers


@Zbysek's answer is probably correct, in that's very likely that the Facebook app is the one that actually performs the verification. Without the source code of this app it's hard to know for sure, but we can infer some things from inspecting the source code of the Facebook API library project, in particular the login process as coded in the AuthorizationClient and Session classes.

  1. First of all, the client verifies that the Facebook application itself is correctly signed. This is expected, since you would not want to provide your login credentials to a fake app posing as Facebook. This is done in the NativeProtocol class (and also in the Facebook class, for the deprecated methods). This is the only mention of signatures in the API, so if there are additional verifications, they are either done by the Facebook app itself, or in the server.

  2. Session.open() eventually creates an AuthorizationClient which tries a series of possible handlers. One of them (the first used, if the SessionLoginBehavior allows it) is the Facebook application itself (for example with KatanaLoginDialogAuthHandler, but there are others).

  3. These AuthHandler objects eventually use tryIntent() to call startActivityForResult() to invoke the Facebook app itself.

So, to sum up, the login process:

  • verifies that the Facebook app is legit,
  • ends up calling an Activity inside the Facebook app,
  • calls it passing the FB application id, and some other data,
  • from an Activity inside your app, via startActivityForResult().

This is a key part, since activities started with startActivityForResult() (but not those started with startActivity()) can use getCallingActivity() to know the identity (package and class name) of its caller.

Therefore, the Facebook app could easily use this information to query the PackageManager, obtain your app's signature, pass that data along with the application id to the server, and validate that they match. And since the Facebook app is itself signed, your app can trust this result.

I admit this is all speculation, but seems plausible enough, given what we know :)

Unfortunately this also means that it's unlikely that this mechanism could be replicated for your own use of guaranteeing authenticity. Unless you are Facebook or Google (Google Play Services has a similar signature verification feature, e.g. for Maps) or can somehow ensure that a second app of yours will also be available on every device.


It is the native Facebook app called through SDK that verifies a signature of the app - by API built in in Android OS - it checks if it matches hash or not. Hash is sort of public key when app is signed by private key.

One could use JS SDK to login user instead of native app and then hash won't be verified (can be spoofed). Anyway they see it as non-issue as in such circumstances user will see in what app does he log in and need to allow access anyway (login flow goes through FB server and it shows app name). You can't spoof uid in Facebook cookie here.

One also possibly could mess with Facebook natve app to make it see non-signed app as some other signed one knowing hash of that other one (but this would be rather hard task if even possible, one would need to crack it, change it and it would work only on system where modified native FB app was installed).


Need Your Help

Documentation for older versions of Bootstrap

twitter-bootstrap

If I am working on a long running or old project which uses an older version of Twitter Bootstrap, where can I find the documentation? (upgrading is not always the easiest option).

Java: Safely typecast a Clone of an ArrayList?

java casting arraylist clone

I would like to make a clone of my arraylist by this code: