I am developing an android application which interacts with my server. For including the SSL layer, I created a self-signed certificate for my server. So, at present when i access my server through a browser, it sends that certificate and once I save it, all works fine on browser.
But I am not sure, how can I move ahead so that my Android app will communicate effectively with the server. The thing I know so far is that I need to generate a keystore (.bks) for my android application and pass it on to TrustManager. I found various tutorials to generate the keystore but I am getting confused at few points:
Will I need any info regarding the server's certificate for generating this keystore?
Is there any way through which I can replicate the browser like functionality in the application? (If the certificate is not from a trusted CA, add it to the list if the user confirms that.)
How will the server trust my keystore?
I might be mixing some of the concepts because I read a lot of articles regarding all this. The articles/questions that I have already referred are:
Bob Lee's blog
Blog on CodeProject
Using OkHTTP
StackOverflow answer
Extract cert from server and add to keystore
Related
I've recently started to learn about security in Android apps and wanted to implement certificate-pinning. Found some useful information by googling around but I stumbled upon storing the keystore password which contains the server certificate.
As I can't trust the Android filesystem to keep my keystore password secret, mainly because any rooted user would be able to dig it out eventually, I'm starting to wonder whether if it is really needed to securily store this keystore password or not, because this keystore will only contain my server's SSL certificate, which is intended to be public.
I can't think about any malicious attack if somebody could decompile my APK and see the keystore password, as the attacker wouldn't be able to modify any of the app's code and thus change, for example, the targeted server IP or even modify the keystore switching my certificate with some other malicious cert which, in combination with the changes the attacker could made on the targeted IP, would make the app work targeting any malicious server (man-in-the-middle-attack).
I found a quite good example of certificate pinning in Android here on github, but sadly the author doesn't bother with storing the passsword securely, as it is hardcoded at the MainActivity.
So my summed up question would be: Is it really needed to protect a keystore password if that keystore only has inside an intended public SSL server certificate?
From the research I did, I found that on this question the OP addresses the posibility of passing null as the password on the Android code. Maybe I could go with this and store the keystore password at my server instead of packing it up inside the Android app.
Also during my googling I found quite useful articles that might be interesting for anybody looking into this question in the future:
Certificate-Pinning in Android explained easy
Securely storing info in Android
Android Keystore for storing keys (WARNING any rooted user can dig out info stored here)
Progress update
- Passing null as the keystore password (as I mentioned above as one of the options) if you've set one when generating it will result in keystore bypass: requests get sent anyway and custom keystore does nothing. No exception is thrown or anything, it just works as if you didn't set any custom keystore.
KeyStore trustStore = KeyStore.getInstance("BKS");
trustStore.load(keyStoreInputStreamFromResources, null);
I went through this link.
I have some couple of questions:
1. What is keystore? And what and why I need to implement?
2. What is TrustManagerFactory and what is 'X509' in this context? Please answer is there is something else other than 'X509'.
3. What details should I know or consult for from my webserver application team? Do I need to know about the any kind of certificates or something else?
My problem scenario: What I am trying to do is to retrieve some XML string over network and it have to secured because it is little bit sensitive.
I am waiting for your answers.
You may not need to study HTTPS in detail to secure your XML. To use HTTPS, you mostly just need to get an official SSL certificate for your domain, and use it in your server. Then the HTTP client, either in the browser, WebView or Java HTTPClient, will know what to do with it.
Read the Java SSL implementation, JSSE documentation for some basics and perspective.
A keystore stores keys or certificates. If the CA that issued the certificate of you server is trusted by Android (i.e., it is already installed in the system trust store), you don't need to mess around with keystores. It should just work. If it is not, you may need to create your own trust store that includes the certificate of your server if it is self-signed or that of the issuing CA if it is not.
TrustManagerFactory produces a TrustManager. It tells your app/system what certificates to trust. Technically there can be other implementations besides X.509, but in practice this is the only one in use.
See 1. Ask them who issued the certificate. Or simply access the site with your browser. If you get a warning or an error, things might get slightly complicated because most likely Android won't trust the server certificate by default either. IF not, your app should just work with an https://myserver/sevice type URL instead of an http:// one.
I've searched everywhere, and found lots of information I cannot comprehend. I'm using a WAMP server and managed to execute a "SELECT name FROM Tablename" query and passed the data to json_encode(). I like the results so far, but now I need to protect the JSON file in the server, making it accessible only to users that run my Android app.
Through my research I found that REST might be a solution for me but I do not understand how I can implement it for my case. Is it possible to have Server-side REST Security, and Client-side as well? I understand that REST is a web service and I read a tutorial where the web service is basically a web page. My priorities are server-side json file, security and speed. The user will not be inserting any information via the Android app. I was thinking of deploying the Android application with the user and password to the specific json file (verification).
It would be helpful if you can point me to a video tutorial, or a tutorial for beginners, related to the subject.
Here are my specific questions?
Can I parse images with JSON?
Is it more efficient to mysqldump --> convert .csv file ---> SQLite? (Securely).
How big can a .CSV file get with say 1 million entries in the database?
How can I accomplish all this?
Please help, thanks.
Solution: Use HTTP Headers
Insecure solution:
use the User-Agent header.
User-Agent: MyAndroidApp/1.0
More secure solution:
First off, you'll need to use SSL so no one can just easily see your secret key.
Second, you can put a secret key in the HTTP header of the request you make from the android app:
X-Android-Secret-Key: fee400be-7d08-45c5-bf7c-ff79c35a838c
You check headers on the server and only serve the file back if the desired header is received. You keep the header somewhat secret but not impenetrable with SSL.
I'm only going to answer your original question on app authentication. Your other questions belong as separate questions.
If it's only your client and your server, you can (and should) use mutually-authenticated 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.
You'll normally store that certificate/private-key in a keystore of sometype (a KeyStore if you're using Android) and that keystore will be encrypted. That encryption is based on a password, so you'll either need to (1) store that password in your client somewhere, or (2) ask the user for the password when they start your client app. What you need to do depends on your usecase. If (2) is acceptable, then you've protected your credential against reverse engineering since it will be encrypted and the password will not be stored anywhere (but the user will need to type it in everytime). If you do (1), then someone will be able to reverse engineer your client, get the password, get the keystore, decrypt the private key and certificate, and create another client that will be able to connect to the server.
There is nothing you can do to prevent this; you can make reverse engineering your code harder (by obfuscation, etc) but you cannot make it impossible. You need to determine what the risk you are trying to mitigate with these approaches is and how much work is worth doing to mitigate it.
We have a web service that should only be called by a specific Android app. What solutions are there for this problem?
The requirement is to not use authentication at all.
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.
You'll normally store that certificate/private-key in a keystore of sometype (a KeyStore if you're using Android) and that keystore will be encrypted. That encryption is based on a password, so you'll either need to (1) store that password in your client somewhere, or (2) ask the user for the password when they start your client app. What you need to do depends on your usecase. If (2) is acceptable, then you've protected your credential against reverse engineering since it will be encrypted and the password will not be stored anywhere (but the user will need to type it in everytime). If you do (1), then someone will be able to reverse engineer your client, get the password, get the keystore, decrypt the private key and certificate, and create another client that will be able to connect to the server.
There is nothing you can do to prevent this; you can make reverse engineering your code harder (by obfuscation, etc) but you cannot make it impossible. You need to determine what the risk you are trying to mitigate with these approaches is and how much work is worth doing to mitigate it.
I guess this will work with proper authentification in place. First post I just stumpled upon was this one:
Securing communication from android to a web service
Hope it helps =)
If you're absolutely certain this web service will only need to be accessed by authorized applications/devices, go with client-side SSL certificates and restrict access at the server to only clients with authorized certs. This has the bonus feature of forcing SSL at all times so you don't like auth secrets over an open channel. Here's a quick guide for Apache, but you could use nginx too:
http://it.toolbox.com/blogs/securitymonkey/howto-securing-a-website-with-client-ssl-certificates-11500
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.