Protect API URL access via hash in Android app

2019-01-17 23:03发布

问题:

In my Android application, the user can submit content to the database which can then be seen by all the other users as well.

This new content is sent to the server via GET request:

http://www.example.org/API.php?newContent=helloWorld

The problem is: If a user finds out what this URL looks like, he could easily sent malicious requests in his browser and circumvent the Android application. Maybe one could decompile the app and find out about the URL.

How can I protect access to this URL and prevent users from accessing this API directly?

Is it a good solution to generate a hash in the application and compare it with a hash generated in the API.php file on the server?

Couldn't one find out how the hash is generated when decompiling the application?

Thank you very much in advance!

回答1:

So the only way to truly protect that URL is by requiring all requests to it be authenticated.

One way to do this is change your request to a POST request and send along some sort of auth token (a simple hash will do) with the request. If the auth token isn't present, simply don't respond to the request. The hash would be something you'd hardcode into both the client and server.

Now the question is how to hide your auth token. As long as you're not open sourcing your code, the only way for someone to get at it would be to decompile your program as you mentioned. To guard against this you might want to look into using proguard (http://developer.android.com/guide/developing/tools/proguard.html).

Something to keep in mind is that this method contains a single point of failure. If your auth token is ever exposed, you're done for (e.g. the HD DVD AACS cryptographic key debacle).

One other way to authenticate is on a per-user basis. As long as a valid user is making a request, you shouldn't really care whether or not the request is coming from the web browser or android app. I think this is a much better way of doing things. By doing this, you can throttle requests on a per-user basis. This however requires you to manage user profiles and the whole can of worm that comes along with it.

All that said, at the end of the day though you shouldn't really care if somebody knows the url to a portion of your API. I don't know your particular use case, but there's got to be a way to design your API so that you don't care how you're getting your requests. Also, if your doing a true GET, then you shouldn't be changing anything on the server. This means that all the 'malicious person' can do is get data off of it. This severely limits the damage they can do. In fact, unless you have sensitive data that you don't want certain people to look at, you don't really have a problem at all. If you do, then you should really think about my per-user authentication solution.



回答2:

Don't trust the client for validation. This is true if its javascript in a web-browser or even some locked down platform like the Iphone.

If the app can make the API calls, then clearly everything needed to make those calls is on the phone ( secret, hash function, API key, whatever), then someone can always dump the phones storage and get all that data. They can then make whatever request they want.

What you want to do is authenticate the user and then validate the input on the server side.



回答3:

Use SSL (HTTPS) for your data transfers. The exchange is encrypted before any data is sent, so anyone listening in won't be able to see either the URL or data that is sent to the server. To verify this for yourself, install Wireshark on your dev system and load the URL into a browser. You'll not see any data in the clear (either the URL or the data that is sent via either GET or POST).



回答4:

You could use a somewhat confusing java method to obfuscate every letter of the URL. So kind of creating your own dictionary in a way which could make the URL possibly appear as 123.3*15*13 or something like that if someone did decompile the APK, they would have no idea. And on that note, you would ideally use Proguard to obfuscate it, so your obfuscation would make no sense to someone trying to reverse engineer.

You could make a short java method like this:

public String confuseString() {
    Stringbuilder sb = new StringBuilder();
    //your real URL would be abc.com, but in the app you have myURL = 123.3*15*13
    //With what I'm saying the * would precede a 2 digit number that represents 1 letter
     for (int i = 0; i < stringLength; i++){
         String letter = myURL.charAt(i);
        if (letter.equals("1"){
            letter = a;
            sb.append(letter);
        } // you would go one to code each character into a letter
     }

}

There would be several more if statements of course, but it would allow you to obfuscate your url without making any server side changes. And if you use Proguard, then that entire method that you create would make absolutely no sense to someone trying to reverse engineer.

You could of course make your obfuscation much more complicated than what I suggested, but it's an idea anyway.

Basically you'd be encrypting the URL in a very confusing fashion.

Here is an answer which may be a better method of encryption or at least give additional encryption:

Java - encrypt / decrypt user name and password from a configuration file