I have client/server data passing all working correctly. Text, Images, etc. My users create blog-type posts on their android device, and upload to my server.. All is done using HTTP Multipart and Input/Output Streams. My issue is - How do I know the client is actually my app and not some script/other hacker app?
I want to avoid abuse scenarios.
- Malicious user A creates a PC script that sends the appropriate form data to my server and is able to spam the server, creating 1000s of malicious posts.
- Malicious user B creates a simple Android App that sends the appropriate form data to my server and he is able to spam the server.
- Malicious user C signs up to my service, Has a valid account and password, and he spams the server using a PC script or Android App.
One idea I have is to force a wait period server side on frequent posts to prevent spam..
But beyond that, how can I check that the person sending data to my server is
- An android device and
- Is running my App to send form data and not another.
I want to avoid SSL as I don't want to register with Verisign, TRUST and go through all of that..
If it's only your client and your server, you can (and should) use SSL without purchasing anything. You control the server and the client, so each should only trust one certificate, the one belonging to the other and you don't need CAs for this purpose.
Here's the high-level approach. Create a self-signed server SSL certificate and deploy on your web server. You can use the keytool included with the Android SDK for this purpose. Then create a self-signed client and deploy that within your application in a custom keystore included in your application as a resource (keytool will generate this as well). Configure the server to require client-side SSL authentication and to only accept the client certificate you generated. Configure the client to use that client-side certificate to identify itself and only accept the one server-side certificate you installed on your server for that part of it.
A step-by-step for this is a much longer answer than is warranted here. I would suggest doing this in stages as there are resources on the web about how to deal with self-signed SSL certificate in Android, both server and client side. There is also a complete walk-through in my book, Application Security for the Android Platform, published by O'Reilly.
I finally got it all working, server and client two-way ssl authentication.
I used the instructions here to setup my own cert authority (ca) http://www.garex.net/apache/
I followed the commands there to generate my own ca, server and client files..
The big "GOTCHA" was that in the "create client certificate" section, the garex.net link uses a 1024 size client key. As it turns out, this was throwing the exception java.io.IOException: Wrong version of key store
To get around the above exception, I had to use only 512 sized keys.. This is done by NOT including the "1024" parameter to the openssl genrsa genkey command..
Finally I want to add a link to a tool I ended up using instead of Portecle.. I found the keytool gui program here of great help and easier to use than the portecle one - http://www.lazgosoftware.com/kse/index.html
This issue was a bit of a pain in the butt so I will keep an eye on this thread.. Feel free to reply if you run into any roadblocks..
You can use a captcha to solve this problem.
- Before submitting the post, request the server for a captcha.
- Server associates a random captcha image with a unique key, and sends the application both the captcha and the key.
- Show the captcha image to the user.
- Send the post, the letters entered by the user and the unique key in your http request.
- Server verifies the captcha letters based on the unique key.
- If captcha verification succeeded you add the post, otherwise you don't.
This should solve all the scenarios.