2

I have an android app that connects to a server through HTTP (notice the abscence of S, also android means Java, so nothing I'll hardcode in my app will be unreachable).

I want to store the password securely on my DB, so I wanted to use bcrypt (with password and salt)

My issue is the following : since I'm on HTTP, I don't want to send the plain password to my server.

Since I'm on mobile and 3G is very slow, I don't quite want to send the salt to the phone first so he can send the already hashed password to the server. (two queries instead of one)

Is there a way to make it work other than using the login + a fixed string as a salt ?

Thanks !

Taiko
  • 143
  • 6

2 Answers2

2

You want to use bcrypt for storage on the server side: that's good. You have to remember why you do that: it is because you fear that the server's storage area may be plundered in some way, and you want an extra layer of protection. The point of bcrypt (or any other similar password hashing function) is to make dictionary attacks more expensive: there is a salt (to prevent parallel attacks on many hashed passwords, and precomputations), and there are many iterations (to make each guess expensive).

You thus want to maximize the number of iterations. This implies that the hashing has to be done on a fast computer. A smartphone running Java code is not fast (a recent enough Android version includes a Java VM with a JIT compiler which will offer not-too-pathetic speed, but the result will still be uncompetitive with the server's abilities). Therefore, you really want the bcrypt to happen on the server side. Even if obtaining the salt from the server was acceptable (from a network latency point of view), the lack of CPU performance on the client side would be debilitating.

Therefore, your problem really is about how to transfer a very sensitive information (the password) from the smartphone to the server, making sure that it does not get intercepted while in transit. Since an app cannot contain secrets (because reverse engineering works, and that's not exclusive to Java), you will have to use asymmetric cryptography, with a public/private key pair, such that the server owns the private key, and the client can make sure that it uses the right public key (and not a fake attacker-controlled key). At that point, you are pretty close to SSL.

Using HTTPS would be the simplest method to achieve what you seek; in particular because the phone already includes all the needed code.

It might be argued that HTTPS implies too many network round-trips. It is conceptually feasible to do better when what you want is a one-way transmission of some secret data to the server; in that case, you can mimic the email model, which then points at OpenPGP. You could asymmetrically encrypt the password to send, using the known server's PGP public key (hardcoded in the app -- that's not a problem, it is a public key), and sending the result as a single HTTP request. This minimizes network traffic, while still relying on an encryption format which has survived some amount of external review. A Google search on "android openpgp library" yields a few useful pointers for the actual implementation.

Thomas Pornin
  • 322,884
  • 58
  • 787
  • 955
0

What you're proposing is still unsafe: since the salt is always the same for a given account, an attacker who listen to the traffic can simply record the value returned by your client and reuse it afterward (this is call "passing the hash").

There are ways to help mitigate that issue but they all end up with the same problem in the end: you might secure the login but everything else (including whatever mechanism you use for maintaining the session state server-side) is still insecure and you end up with an utterly broken security model.

So, please, do not try to do it yourself: your problem is an age-old one and it has a solution that is easy to implement, easy to deploy, widely supported and cheap: use HTTPS.

Stephane
  • 18,607
  • 3
  • 62
  • 70