views:

284

answers:

4

Hello all... I have recently written a socket server in PHP that will be handling communication between an Android phone application and my PHP webserver. Due to the fact that Android doesn't natively support push style notifications we are going to be using our webserver as the middleware layer to handle our 'pushes'.

The socket server is stable, runs well, and seems to scale nicely. While I would eventually like to re-write this in C I don't have the skill necessary to do that right now so I am going to be staying in PHP for at least a short while. As of this moment our Android emulator is able to communicate through the server, get pushes, etc. so that part is all covered.

My concern is that, right now, anyone can open a socket to my server and will be given a client connection. While we won't be passing sensitive data back and forth I don't want to allow just anyone to connect over and receive broadcast information, eat up my resources, and clog my server in general.

The question is, how do I secure a server like this? Let's assume that I am running on port 25,000--can I set up some sort of SSL layer on that port and expect devices like the Android to be able to communicate over that port without any special protocols or jumping through hoops?

I have considered asking the connecting clients to authenticate their user against our user database before being given a client connection, but that would require the passing of credentials in plain text over the network which I am NOT about to do.

Any suggestions on this would be very helpful--I am rather new to straight TCP communication from PHP and feel like I might just be missing something simple that allows for authentication on this level.

Additional information: If I am able to get a valid username and password securely I would be using MySQL to validate the user and then accept/reject their connection based on the results of the query.

Thanks in advance..

+1  A: 

First, I hope you've implemented your PHP socket server in a fashion that allows more than one client to be connected at the same time. This is not as trivial as it should be given the absence of threads in PHP, but it's certainly.

Now, if you already have a socket server implemented, adding TLS support is easy. Just run stunnel and have your PHP socket server only accept requests on the local interface.

Artefacto
Oh yeah, I am handling multiple clients without any issue at the moment, so that part is covered. I will take a look at stunnel and see what that looks like. I am not sure how I can use only the local interface for connections UNLESS stunnel somehow handles the inbound connections to the server--more research will answer that it looks like.
angryCodeMonkey
@angry Yes, that's what stunnel does. It relays inbound traffic after decrypting it and encrypts outbound traffic.
Artefacto
A: 

I don't think SSL is really going to solve your problem. At best with SSL you can provide each client with a client certificate and do client certificate validation on the server. But you'll need to manage tons of certificates then. Or give everyone the same client certificate (not a good idea).

You'll have to authenticate the client using his credentials. You are right that you don't want to send the credentials in plain text over the network, but there are simple alternatives. Take a look at e.g. HTTP Digest Authentication (http://en.wikipedia.org/wiki/Digest_access_authentication) or xAuth (http://dev.twitter.com/pages/xauth). You don't have to implement these techniques over HTTP; you can just as well send a challenge (a realm) over a simple tcp socket after you have accepted the connection. The client should then send a valid response within a short timeframe or the server aborts the connection.

By the way, did you consider HTTP streaming? See http://ajaxpatterns.org/HTTP_Streaming It would probably make your life a lot easier as you can rely upon some other service (e.g. Apache) doing the hard work for you, and you can focus on the business value of your application.

schuilr
@Schuilr - That is an interesting idea but I'm not sure that would work for our Android setup. The reason I went with sockets (instead of just polling for data) is to conserve battery life on the mobile device. I may be wrong, but I would anticipate a long-lived HTTP socket remaining open might create more overhead with headers and might eat up too many resources. I will keep this in mind though in case I can't figure out how to get this all locked down.. Thanks!
angryCodeMonkey
The request/response headers are sent only once, and then the server and client just keep that connection open a really really long time. If the client wants to send something he can abort the connection, send a new request (with the payload) and continue holding a long lived connection again. As long as there is no data going back and forth the connection isn't doing anything. You may want to let the server send a "NOOP" from time to time though, so proxies don't kill the connection
schuilr
Also: port 25000 is blocked from my office. Going through HTTP with this allows use of proxies and firewalls are much friendlier on this port.
schuilr
A: 

you might want to consider: Cloud to Device Messaging : http://code.google.com/android/c2dm/index.html

The only drawback is that it is only supported by android >=2.2

mhughes
@mhughes - Thanks! You did mention my exact issue with using that service though. We are going to be supporting devices < 2.2 for a long while (unfortunately) so I have to have something that will work for darn near everyone.
angryCodeMonkey
A: 

Not sure why you guys didn't use some off the shelf messaging library/server for java, then create an android service that connects to the message broker and handles all initial authentication. The service would simply sit there and wait for any incoming messages.

(I'm pretty sure that listening for network data doesn't power up the radio, only when the data is actually there that the radio powers up. I suspect this is how C2DM works.) This is better then polling because you're only waiting for data. You're not constantly sending packets requesting data. But you knew that already.

I did this, (I used the rabbitmq-java library and the rabbitmq message queue server) and had push style notification for my app in no-time. Even with Android 1.5 devices.

About security:

You could also implement your own security but without having to send plain-text passwords. Simply encrypt the passwords using something like MD5 before passing it through the network.
Then compare the encrypted password with the encrypted password you have on file. This way, only encrypted passwords will go through the network.

Miguel Morales
MD5 hashing a password doesn't make it safe to pass it in plaintext.. Especially since sites like this http://md5.rednoize.com/) have been mapping hashes and are making it easy to decrypt common passwords. Also, we are not running Java on our servers so that would require a lot of overhead to run an off the shelf app just to authenticate--plus our authentication would have to be customized to our app so not sure how well that would work. Thanks though!
angryCodeMonkey
You can use something stronger than MD5 and wrap the connection in SSL.Ideally you should: SSL + Crypted(password) -> ServerAlso, I meant to suggest for you to use an off the shelf *messaging* server that includes built in authentication. It could replace the php socket server you built altogether. (i.e. You post messages from your server app to the mq server, the connected clients would then receive whatever messages they're meant to receive.) You can use many language with these mq servers.Some of these MQ servers support SSL and various authentication methods.Anyway, good luck
Miguel Morales