2

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.

  1. 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.
  2. 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.
  3. 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..

mac
  • 42,153
  • 26
  • 121
  • 131
Daniel Guillamot
  • 843
  • 2
  • 9
  • 18

3 Answers3

2

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.

  • Thanks jeffsix. I went ahead last night and read a lot about self-signed certs and keys. I got as far as creating my own certs and keys and keystores. Tonight I am going to integrate them into my server and app. – Daniel Guillamot Dec 08 '11 at 06:47
  • Ah, I also went ahead and purchased your eBook.. Thanks for the help! – Daniel Guillamot Dec 08 '11 at 06:48
  • As I am just getting ready to make the switch to SSL. Once question I have is, how far to take it? It's an IM application. So, should I just go ahead and use SSL for every transaction? Or is it okay to just use it for login/authentication? – Daniel Guillamot Dec 08 '11 at 07:42
  • Right now I am tempted to use it for every transaction with the server. Since that way, any confidential messages that my users are passing are encrypted over the wire. Are there any huge disadvantages to that? Will processing the SSL slow everything down? Only one way to find out I guess but this is where I am leaning atm. – Daniel Guillamot Dec 08 '11 at 07:43
  • 1
    I would advocate for using SSL for everything. Things will slow down a bit, but not to the point where it should negatively impact the UX for your described usage model. Plus, if you only used SSL for an authentication ceremony and then went to normal HTTP, you'd be exposing the session cookie/token over the (now unencrypted) link, which could lead to session hijacking. –  Dec 08 '11 at 17:40
  • Oh, and thanks for the purchase! I'd love any feedback you'd have. –  Dec 08 '11 at 17:40
  • Well, I've spent 2 days fiddling with client-side authentication but still can't get it working.. Server-side ssl is all working using a Server.jks (in my webserver) and a Server.bks (in my android app)............ Then I just repeated the exact same steps and got a Client.jks (server) and Client.bks (android app). I set 'need-client-auth' in my webserver and it appears to be trying to authenticate the client, but everytime I get 'bad cert' and 'null cert chain' errors... – Daniel Guillamot Dec 10 '11 at 17:57
  • I have a feeling there may be more to creating the Client.jks and Client.bks.. Should these files be created exactly as the server? What should I put in my android app for client-side authentication and how do I create it? I'd love to have the keytool commands for client-side authentication the way your (excellent) book has it for server-side.. Could I trouble you for a bit more help? – Daniel Guillamot Dec 10 '11 at 18:01
  • I got further today.. Set up a proper CA and generated all my keys and certs and signed them all with the same CA.. All using openssl.. Ended up with a server cert, key and certificate signing request.. Also got a client cert, key and certificate signing request. all signed by the one CA... My server works great with server-side SSL check only... I then created a p12 file out of my client cert, imported it into Google Chrome, and turned on client ssl authorization on my webserver. That worked great also.. So browser-based server+client ssl authorization is working like a charm -- but~ – Daniel Guillamot Dec 11 '11 at 15:41
  • When it comes to the android app... Everything works okay with server-side only ssl authorization (using TrustManager and the server cert)... But For the life of me I can't get the client ssl authorization to work.. the server keeps reporting "bad certificate - null cert chain"... the android log reports bad certificate as well.. I tried with just the client cert in a bks store.. then added the client key retried... then added the server cert retried.. then added the CA cert retried.. all with the same error... my code is: – Daniel Guillamot Dec 11 '11 at 15:43
  • KeyStore clientauthKeys = KeyStore.getInstance("BKS"); clientauthKeys.load(context.getResources().openRawResource(R.raw.allcertsandclientkeypairbks), "mypass".toCharArray()); KeyManagerFactory keyMgr = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); keyMgr.init(clientauthKeys, "mypass".toCharArray()); SSLContext privateSSLcontext = SSLContext.getInstance("TLS"); privateSSLcontext.init(keyMgr.getKeyManagers(), trustMgr.getTrustManagers(), new SecureRandom()); – Daniel Guillamot Dec 11 '11 at 15:44
1

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

Daniel Guillamot
  • 843
  • 2
  • 9
  • 18
0

You can use a captcha to solve this problem.

  1. Before submitting the post, request the server for a captcha.
  2. Server associates a random captcha image with a unique key, and sends the application both the captcha and the key.
  3. Show the captcha image to the user.
  4. Send the post, the letters entered by the user and the unique key in your http request.
  5. Server verifies the captcha letters based on the unique key.
  6. If captcha verification succeeded you add the post, otherwise you don't.

This should solve all the scenarios.

Arnab Chakraborty
  • 7,442
  • 9
  • 46
  • 69
  • Thats a good suggestion. I think it won't work so well in my particular app because it may be a bit inconvenient. Is there anything I can do in-code so that the server knows the client is my android app? – Daniel Guillamot Dec 07 '11 at 06:15
  • Captcha is a widely accepted practice. You should really consider it. Other than that, I cannot think of anything else right now. You could use a shared key, but then you'll have a single point of failure, if someone comes to know your key they can easily spam your server. – Arnab Chakraborty Dec 07 '11 at 06:41
  • Hmm. The applicaiton is a chat application. So users, in groups of 2, 3 or 4 are having real-time chat. In other use-cases, their chat is forum message-based and the discussion is available publicly. For the chat user case, I think the captcha might be a bit much. But I am less worried about hackers spamming that.. It's more the message-board style discussion use case. Such as this stackoverflow discussion space.. We don't have a captcha here.. Hmm – Daniel Guillamot Dec 07 '11 at 06:45