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);
Related
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
I've read about Keystore which is in fact a repository of security certificates – either authorization certificates or public key certificates – used for instance in SSL encryption.(by Wikipedia).
Android developers use the Keystore to store their encryption keys in it, instead of
embedding the encryption key inside the android application. That's supposed to solve the problem of a hacker which is decompile their app and get the encryption key the is used by the app.
Whenever you want access the data inside the Keystore you have to specify a password. What prevents the hacker from decompiling the app, extracting the Keystore's password, and then gathering the encryption key inside the Keystore?
Or maybe I got it all wrong?
They are likely storing that key encrypted in the keystore itself. To access the key store, you will need some combination of the user's passcode for unlocking the android device and/or a device specific code such that only that device can decrypt the keystore.
I'd like to have secure communication between my Android/iOS app and my Internet-accessible backend service, so I'm investigating HTTPS/SSL.
If I create self-signed certificates, then put a client certificate in the app and cause the backend service to require that client certificate, is this truly secure?
Here's why I'm asking. It seems that the client certificate could be "hacked" by interrogating the .apk. The client certificate is just a string constant, right? That means anyone could use the client certificate to access my backend. Is the .apk (and iOS equivalent) sufficiently opaque to prevent the client certificate from being discovered?
Are you doing client side authentication with certificates over SSL? Not that it really matters for this question. Any private keys you store in your app is accessible to an attacker. Each client should have it's own certificate and key pair, to prevent a mass compromise. Your server should also enforce protections, ensuring a compromised client can't just request anything.
This is true for any authentication scheme. If you embed passwords, API keys, decryption keys, whatever. Anything on the device should be assumed to be accessible.
The added security from certificates in part comes from there being nothing to brute force. If you went the username/password route for each clients, passwords can be guessed. Same with API keys (albeit they are longer and harder). With certificates, it's an entirely different class of attacks, and a considerably harder problem.
But, most importantly, the backend service shouldn't allow the app to do anything it wouldn't normally do.
Now, dealing with certificates, you're going to have a whole host of other problems. You probably want to sign each client certificate with your self-signed CA cert. Managing that CA cert can be problematic, depending on your use case. Are you going to generate these client certs on the fly, or manually yourself? Meaning, is this an app that a million people can download, and you need an automated system for generating them? Or is this a private/internal app that you personally will handle generating certs?
The certificate is harmless. It is the private key that needs protection, and it is only as safe as the device itself, no safer. Distributing the certificate and private key with the application just means that anyone who has the application has the key, so it doesn't provide you any security whatsoever. I think you need some kind of post-install registration step.
Typically, client SSL certificates are stored in keystores (BKS formatted in the case of Android) and the keystore is included as a resource within your APK. Keystores are encrypted and protected with a password. So, that client certificate cannot be readily extracted from an APK, as it is stored in an encrypted form.
Now...what do you do about the password? Here is the crux of the matter and you have two alternatives.
If you want your application to be able to communicate with the server (so, to be able to access the certificate) without user interaction, you will need to embed the password into your application and then, yes, an attacker could reverse engineer your code to find it, grab the keystore, and then decrypt it to recover the certificate. You can apply techniques like obfuscating your code so that it is harder for an attacker to do so, but this will just slow someone down and not prevent it.
Your alternative is to prompt the user for a password every time your application communicates to the server and use that to decrypt the keystore (or ask when the app starts and cache the certificate for a certain amount of time). The advantage here is that if someone reverse engineers your APK, they will find the encrypted keystore and no password so your certificate is safe. The disadvantage is having the user provide the password.
Which approach is best? It completely depends on the sensitivity of the data you are concerned with and the level of risk you are willing to accept. Only you can answer that question.
Daniel Guillamot, some tricks I've come over:
split server side key. Make the passphrase for the SSL-key be the result of string-in-app XOR string-fetched-from webservice.
make the string-in-app be created by calling some app-functions, instead of hard coded string.
deny tracing the app while it's running, to avoid someone picking up the final passphrase when it's calling the decryption of the private key. Ref: http://books.google.no/books?id=2D50GNA1ULsC&lpg=PA294&ots=YPQQ7DLjBD&dq=The%20example%20just%20shown%20demonstrates%20how%20calls%20to%20ptrace%20can%20be%20hijacked&hl=no&pg=PA293#v=onepage&q&f=false
I'd love to hear more if anybody have other ideas.
APK can be accessed and copied, so putting anything in it won't help. Activation and maybe binding the certificate to the device after installation would be necessary. Binding can be done for example by putting the IMEI of the device to one of certificate extensions and passing the IMEI together with the certificate by your application (or, better, pass IMEI after authentication and establishing the secure channel).
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'm developing an application for android and I have to maintain a secure communication with a server through a pair of private and public key. Which is the safest way to storage the private key in my apk? Obviously I'm going to obfuscate the code but I want more security. I have thought the following option:
If I create a native share library with the methods for sign the transaction information, The apk only have to contain the .so file and this file is in machine code, so the decompilation could be difficult, isn't it?
any ideas?
Thanks
Store the keypair in a keystore and include the keystore as a resource in your APK. Android tends to prefer the BouncyCastle Key Store (BKS) format. Keystores are specifically designed for this purpose.
Note that you should protect the keystore with a password and your application will need to know that password to access the keystore. So, you're left with needing to ask the user for a password to access the keystore or include the password in your code (obfuscate it to make it harder for an attacker to reverse engineer). If someone is going to the trouble of reverse engineering your application to recover your encrypted keystore and the password needed to access it, including that password in a compiled native library will not present much of an additional hurdle.
However, you may not need to do this anyway. If your goal is to protect/encrypt the data in transport to/from the server, use SSL/TLS. If you're not doing client-side authentication, your server needs an SSL certificate but your client does not; the protocol takes care of generating the encryption keys for you in a safe manner. If you do want the server to authenticate the client (make it so your server only talks to your clients), you'd need to install a client-side SSL certificate with your app ... this is the private key that you're probably thinking about.
I'll also point you to Application Security for the Android Platform. This book (disclaimer: I wrote the book) has an entire chapter talking about how to design secure Android app-to-server communications, with code examples to illustrate how to implement the appropriate protections. You may want to give it a read.
First of all, in order to implement secure communication between your client application and a server, conceptually speaking, you need only the public key of the server. That allows you to establish a one-way trust relation ship with the server and to establish a secure session, in which the identity of the server is guaranteed.
While certainly the above method does not provide two-way trust (the client cannot be identified to the server), when establishing the communication channel in most applications, this level of trust is not really required.
If your requirements are to provide client authentication to the server using public/private keys then things get more complicated because if you put the key in the apk, no matter how much you obfuscate it (including embedding it in a native library) it will only slow down a dedicated nefarious user.
The only way to store the private key with the client is to encrypt it. But then you have a similar issue of where to store the decrypt key. The easiest solution is to generate a public/private key pair for the user of the client application and ask the user to provide a symmetric encryption/decryption key (which the user will always have to type in) to decrypt the private key each time the user is using the application.
The alternative would be to use some kind of dedicated cryptographic hardware device similar to a smart card that would store the private key securely but you still have the problem of authorizing your application to read the key from the device (not to mention the complication of interfacing with said device).
Now, the question you have to ask yourself is this: "Who are you trying to prevent from reading the private key?" (of course after answering the other question: "Do you really need a public/private key pair for the client").