Feb 9th, 2012, 03:43 AM
Secure communication between app and webservice
I am building an Android app that users can use to read (and maybe later post on) a forum for a particular website. Since the forum has no API to communicate with it whatsoever (it seems to be a custom built forum), I am stuck with parsing the HTML code of each page manually. In order to access a page though, a user must be logged in to the main website. I can log a user in by sending a HTTP GET request to the login page with the (plaintext) username and password. I get a cookie back which i then send along with any further requests to authenticate the user.
Now, for various reasons, I decided I want a webservice in between the app and the forum. The idea is that the app sends a request to the webservice ("give me the details of page xyz"). The webservice in turn uses a HTTP POST request to get the HTML source, parses it and sends back (via json) the relevant details (thread title, page, author, etc).
Just to provide details: the app is written in Java (Android SDK) and the webservice is an ASP.NET .asmx webservice written in C#.
I have everything working just fine, I'm just not sure how to approach the security issues. Since the webservice requires the plaintext password, I have to somehow send it from the app to the webservice (I cannot hash it). Obviously this message could get intercepted , and the user could get compromised. The main website uses the same login details and contains sensitive information that absolutely should not get stolen.
I have a couple issues really, and a couple of possible solutions, but I'm unsure what the best solution for all problem is. The problems are basically:
1. How do I make sure a password cannot get stolen by intercepting a message between the app and the webservice? In other words, how do I send the password in a secure way?
2. How can I store the password on the Android device securely, so that the user doesn't have to type it in every single time they want to use it?
3. How do I authenticate a user on my own webservice, once he is logged in?
For problem 1, I seem to have two options: encrypting the password myself, or using SSL (HTTPS webservice). I have looked at both, and I'm unsure which solution to use (also related to problem 2, as I will explain).
I can encrypt the password on the Android app side using an asymmetric encryption algorithm (RSA). On the webserver side, I can decrypt the password again and get the plain text password back, so I can send it to the login page of the forum. I use asymmetric encryption so that it is no problem if someone can decompile the Android app and find the key used to encrypt it; that key is the public key and everyone may see it. The webserver has the private key which is used to decrypt the message again. Since nobody should be able to see the private key on my webserver, nobody can decrypt the messages. The only problem I can see is that the private key might get leaked due to a bug or webserver hacked or whatever, in which case every message could get decrypted. To avoid that, I could use a new key for every transaction; the webserver creates a public and private key, sends the public key to the app, which encrypts the password with that key, and the private key is kept a secret and is used to decrypt the password afterwards. However, there's a problem with that in problem 2 as you will see.
People have adviced me not to use encryption myself, but rather use HTTPS. I have to say I am not very familiar with HTTPS (I know it is used for secure communication but that's about it), and my webhost does not include an SSL certificate, so I will have to buy one, which at the moment is my main 'concern'. If HTTPS is really the only good option I will buy one, but for now I want to explore other options too... Furthermoer, HTTPS also gives me a problem in problem 2.
Problem 2: I want the app to be able to store the login details for a user, like many other apps and browsers / websites do, so they don't have to enter them every time. I am a little hesitant about storing the password as plaintext in the Android device though, it seems very insecure (although it would probably need to get stolen or something for the password to be compromised).
If I use my own encryption to encrypt the password however, I don't have to store the plaintext, but I can just store the encrypted password instead. Without the private key, it's useless to anyone except my webservice, so that seems secure. Same problem exists though; if the private key would leak out, passwords could be compromised.
Using a different key pair for every transaction was a solution to that problem, but then I can no longer store the encrypted version of the password (because the encrypted version is different every time due to using a different key), I'll have to store the plaintext password.
If I use a HTTPS connection, I have the same problem; I will have to store the plaintext password on the device in order to remember it.
So in this regard, it seems using my own encryption is giving me an advantage (besides the fact that the key might get leaked).
Problem 3 is slightly different. To view, for example, the threads within a certain forum 'xyz', my webservice has a webmethod 'GetThreadList', which accepts an url (the url to the forum page) and parses the html, returning the relevant details of the threads in that forum. Before a user can access that though, I need them to login. So I also have a webmethod 'Login(username, password)'. This logs them in to the forum website and stores the cookie I send along with every further request for that user.
In order to make sure a user is logged in for every request (like getting the list of threads), I also need to verify which user is asking for the list of threads. So the GetThreadList method also accepts a username. I then check a dictionary of logged in users and their stored cookies, and use the corresponding cookie for that user to perform the request.
The problem here is that there is no longer any authentication at this point: once a user is logged in, all it takes is the username to perform further requests. Alice might log in with her credentials, but if Bob happens to know the webservice he can simply call the GetThreadList method with the username "Alice". Bob doesn't need an account on the forum, Alice has logged in so Bob can access the forum with Alice's account.
How do I avoid this? Do I have to send the password along with every single request again (encrypted again)? That seems silly. Could I somehow create a cookie, just like the forum itself does, which the android app then uses to authenticate the user, instead of the username / password ? I guess I could (but I don't know how), but then I have a similar problem: how do I securely send the cookie back from the webservice to the app? If someone would intercept that message, they could use that same cookie to access the forum just like they could use the username before... I'm a little stuck on this step; how can I make sure a user is authenticated on my webservice before he can use it?
So to summarize I guess:
1. I need the plaintext password of a user on the webservice, but I cannot risk someone intercepting it. So I need to send it securely, either by encrypting it myself or by using a secure HTTPS connection. Which is better and why?
2. I want to remember the login details in the app so the user doesn't have to supply them every time. I'd rather not store the plaintext password though. If I encrypt the password myself with a fixed (non-changing) public key, I can store the encrypted password which seems a lot more secure. A fixed key however doesn't seem like a good idea in case the private key gets leaked; so I want to use a different key every time. However then I can no longer store the encrypted password.
3. Once a user is logged in, how do I authenticate him on my webservice for any further requests without the 'danger' of someone else impersonating him by just sending his username (or his cookie data) along? This is the least of my worries actually, the worst that could happen is that someone without an account might be able to view the forum. That's not a big problem, as long as the password doesn't get compromised.
Sorry for the huge post... But I want to make sure that I use the best option Thanks for any help!!
Click Here to Expand Forum to Full Width