4
votes

I have been doing a lot of research recently on securing my app engine. Currently, I've been reading through the question below and the links in that question:

How do I restrict Google App Engine Endpoints API access to only my Android applications?

However, it doesn't answer my problem. My question is similar to the question above, restricting access to my endpoint API to only my app. The guy seemed to have got it working when he inputs a correct email into the credentials.

My question is if I can achieve the same results without having to input any credentials. I want it so that only my app can use my endpoint API so to prevent other apps from abusing it and using up my quota. I already got a client id for my android application, and have placed it within my @API annotation. To test if it worked, I made a random value for the client id in the @API notation of another api class. However, my app was still able to use methods from both class. Any help?

-Edit-

From reading from the docs and researching further, the endpoint way of authorizing apps is by authenticating the user and for my API to check if user is null. My question is that in the process of authenticating the user, is Google somehow able to read my app's SHA1 fingerprint and authorize it to its list of client ids? If so, how can I replicate this process in my endpoint so that I check the SHA1 fingerprint of the app making the request and compare it to a set value? I don't understand the mechanics behind the endpoints very well, so correct me if I am understanding this wrong.

2
Hopefully someone can provide you with a great answer, but I think it will prove difficult. The reason there are so many unofficial Snapchat clients, for example, is because of the ease in which the unofficial apps are accessing Snapchat's App Engine endpoints. If it could be done I would like to think Snapchat would have taken action by now.Amru E.
But somehow Google is able to restrict API access when authenticating users by authorizing the app's client id. How does it do that? I will edit my question to be more specific.noraacee
@AayCee, Did you ever get this working as described in your edit? I'm facing the same problem.myanimal
Sorry for the late reply. No I was never able to figure out how Google was able to read my app's SHA1 fingerprint or if it ever did. I came up with two solutions. One is to have my app send a secret phrase and my server will verify that phrase. However, this method only provide temporary security because once the app is public, people will be able to reverse engineer the app and read the secret phrase. My only plausible solution for now is to structure my server in such a way that it will not return any information unless specific requesting information is provided.noraacee

2 Answers

2
votes

If the android app has access, then the user has access. A motivated party has many options for inspecting your protocol, including putting the device behind transparent proxy or simply running the app through a debugger. I do suggest running your app through ProGuard before publishing, as this will make the process [a bit] more difficult.

Ultimately, you'll need to make your appengine API robust against untrusted parties. This is simply the state of the web.

0
votes

How you can protect your endpoint API is described here: http://android-developers.blogspot.com/2013/01/verifying-back-end-calls-from-android.html

The secret is that you request a token from Google Play using the following scope: audience:server:client_id:9414861317621.apps.googleusercontent.com where 9414861317621.apps.googleusercontent.com is your ClientId.

Google Play will look up the id at your endpoints app and return a Google-signed JSON Web Token if it finds the id. Then you pass that id in with your request. Above article says you should pass it in with the body. I would possibly rather add another parameter for that because otherwise you can't pass your own entities anymore. Anyway, your server backend receives the token, and you ask Google as described if it is authentic, before you process the API request.

If you pass in the token using an extra parameter, you can catch it on the server side by adding HttpServletRequest to your endpoint signature and then using request.getHeader("Yourname") to read it out. Make sure you never add the parameter as a URL parameter as it may be logged somewhere.

public void endpointmethod(

        // ... your own parameters here

        final HttpServletRequest request
) throws ServiceException, OAuthRequestException {
    request.getHeader("YourHeaderName") // read your header here, authenticate it with Google and raise OAuthRequestException if it can't be validated

On the Android side you can pass in your token when you build the endpoint api, like this, so you don't have to do it with each and every request:

    Yourapiname.Builder builder = new Yourapiname.Builder(AndroidHttp.newCompatibleTransport(), getJsonFactory(), new HttpRequestInitializer() {
        public void initialize(HttpRequest httpRequest) {
            httpRequest.setHeader(...);
        }})

Hope this helps you make your endpoints API secure. It should.