10

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!

caw
  • 30,999
  • 61
  • 181
  • 291

4 Answers4

20

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.

Kurtis Nusbaum
  • 30,445
  • 13
  • 78
  • 102
  • Thanks for this detailed answer :) You said I should only use POST to make API calls which modify data on the server. But what I do is: If the user wants to "upvote" item 123 I call: http://www.example.org/API.php?item=123&vote=up Is this a bad approach? What bothers me is that one can easily look up the function which generates the auth token when decompiling the application, can't one? So every "attacker" could easily generate the correct hash values on his own?! – caw Oct 10 '11 at 14:35
  • Two things. One, that isn't the "correct" approach. Like I said, you should only use GET for things that don't cause change. I should be able to type example.org/API.php?item=123&vote=up and get a consistent web page. Second, if you're doing this for a user then you should definitely use my per-user authentication method. Thereby only allowing valid users to vote. Like I said in my answer, if you're really worried about people looking at your code, you can use progaurd. – Kurtis Nusbaum Oct 10 '11 at 15:06
  • 1
    Thank you very much for your comment again! Probably a stupid question but: Why should I use POST instead of GET for modifying actions? I don't see the advantage in terms of security ... And: Proguard just makes reading your code more difficult, but it doesn't make it impossible ;) How do other apps handle hash generation for Android? – caw Oct 11 '11 at 16:51
  • 1
    If you really want to know the difference POST and GET you can google it. I found this article which from my skimming seems to provide a good explanation: http://www.cs.tut.fi/~jkorpela/forms/methods.html . As far as proguard goes, you're never going to 100% make your code obfuscated. I not aware of any way to make Java completely 100% undecompileable. This stands to reason because at the end of the day the computer still has to decode and in run it, so there will always be a fixed amount of order to the code. – Kurtis Nusbaum Oct 11 '11 at 19:09
  • Thanks for this great link! So using GET just for retrieving information and POST for updates made to the server is just a recommendation. A reasonable one, of course. And the main cause for distinguishing between GET and POST is that browsers show a warning message if one tries to refresh a POST site. But this does not matter in an API ;) I should perhaps switch to POST, though. But my question is still open: Are hashing functions in Android apps safe or not? – caw Oct 12 '11 at 14:38
  • 1
    @MarcoW. Hashing functions are just as safe on android as they are any other platform. – Kurtis Nusbaum Oct 14 '11 at 13:38
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.

imichaelmiers
  • 3,449
  • 2
  • 19
  • 25
  • Thank you for this answer :) I dont't want to validate the API calls on client-side, of course. But the rest of your reply is exactly what I am concerned about. So in your opinion, user-authentification is the only way to protect access to an API for Android apps? – caw Oct 19 '11 at 14:28
1

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).

Alan
  • 3,715
  • 3
  • 39
  • 57
  • Thanks, HTTPS is a good concept to prevent others from listening to secret information sent to the server. But it does not solve the problem of hash generation functions which can be reverse-engineered. – caw Oct 19 '11 at 14:26
  • You can than add authentication, be it a hash or HTTP authentication, or cookie based, or oauth, or... But without encryption it will probably be trivial to bypass. – Slartibartfast Oct 19 '11 at 15:48
  • When you just send a hash to the server for authentication means, how could one bypass this authentification? From just listening to the auth tokens sent to the server you cannot conclude how these hash values are generated (next time). – caw Oct 20 '11 at 21:16
0

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

Community
  • 1
  • 1
Reed
  • 14,703
  • 8
  • 66
  • 110
  • Thank you very much for this detailed answer and the interesting approach :) But couldn't I just use any encryption algorithm instead? And: When someone tries to reverse-engineer the code, he'll also find this obfuscation function and he'll understand how the obfuscated string has to be translated back, right? – caw Oct 21 '11 at 12:18
  • Yes, you could use any encryption algorithm. The more complicated, the better of course. And Technically, someone could reverse-engineer the code, but it would be really difficult because proguard makes the code very difficult to read under most circumstances. So yes, it would still be possible to be reverse engineered, but it would make it MUCH harder if you implemented the encryption properly. – Reed Oct 21 '11 at 21:55
  • Thanks for the additional comment, Jakar! I really appreciate your idea. But I don't get the reason yet why this function should make reverse-engineering more difficult than ProGuard does already!? Could you explain that? – caw Oct 27 '11 at 19:18
  • You're welcome. :) The more code you add, the more it obfuscates, so the more confusing it makes the code. And in my exmaple I did `letter.equals("1")`, but if you define in the class body `final String xqt = "1";` then do `letter.equals(xqt)`, then I believe Proguard will place xqt into a different class and reference it in an obscure manner. But essentially, the more you add, the more it obfuscates, therefore the hard it is to reverse engineer. – Reed Oct 27 '11 at 21:03
  • While it is good to obfuscate your code regardless, it still would be a good practice to manage some kind of user login with a password requirement. That way, only valid users can upvote or whatever. – Reed Oct 27 '11 at 21:07