9

I'm working on an application for iOS which will have the user fill out their password. The password will then be posted to a PHP page on my site using either POST or GET. (It must be plaintext because it is used in a script.)

Besides HTTPS, is there any way to secure the password? Encrypt it in Obj-C and then decrypt it in PHP?

NOTE: The username is not sent... only the password is posted to the server.

EDIT: To clarify, David Stratton is correct... I'm trying to prevent malicious sniffers in public locations from simply reading clear text passwords as they are posted to the server.

citruspi
  • 6,709
  • 4
  • 27
  • 43
  • 2
    Short answer: challenge response. – Halcyon Mar 29 '12 at 21:59
  • I agree with @FritsvanCampen that you should use a challenge response. Whatever you choose, do **not** send the password using GET; always use POST. GET's can be cached by any entity in between (proxy servers, etc.) and, in normal browsers, show the querystring and save it to the history. – Joshua Mar 29 '12 at 22:03
  • 1
    He's talking about preventing sniffers from picking it up if he's asking about an alternative to https. How does that short answer - "Challenge Response" apply? (Not criticizing, just hoping for a chance to learn, and hoping you're going to expand on that answer.) – David Mar 29 '12 at 22:03
  • Try AES to encryption and use BASIC auth to set headers. – Hamza Waqas Mar 29 '12 at 22:03
  • 2
    There is really no trivial way to "securely send the [plain text] password" outside of HTTPS. Just use the tools available. –  Mar 29 '12 at 22:05
  • And what tools would those be? – citruspi Mar 29 '12 at 22:06

3 Answers3

9

Challenge response outline

Lets assume you have one-way hash function abc (in practice use md5 or sha1 a cryptographically strong hashing algorithm for PHP see: password_hash).

The password you store in your database is abc(password + salt) (store the salt separately)

The server generates a random challenge challenge and sends it to the client (with the salt) and calculates the expected response: abc(challenge + abc(password + salt))

The client then calculates: abc(user_password + salt) and applies the challenge to get abc(challenge + abc(user_password + salt)), that is sent to the server and the server can easily verify validity.

This is secure because:

  • The password is never sent in plaintext, or stored in plaintext
  • The hash value that is sent changes every time (mitigates replay attack)

There are some issues:

How do you know what salt to send? Well, I've never really found a solution for this, but using a deterministic algorithm to turn a username into a salt solves this problem. If the algorithm isn't deterministic an attacker could potentially figure out which username exists and which do not. This does require you to have a username though. Alternatively you could just have a static salt, but I don't know enough about cryptography to assess the quality of that implementation.

Halcyon
  • 57,230
  • 10
  • 89
  • 128
  • This is good for authenticating and is effectively what HTTP Digest Auth does. This is not so good for sending the plain text password to the server for reason XYZ. –  Mar 29 '12 at 22:08
  • Thank you for the prompt response. The problem here is that the password is never stored in any database. The password is sent to the script, the script runs some stuff, and an output is printed. – citruspi Mar 29 '12 at 22:09
  • The database isn't essential. All you need are the three pieces of information: `password` (the secret), `salt` (public knowledge, enables you to store the encrypted `password`) and the `challenge` which varies every time. With this combination you are cryptographically safe. – Halcyon Mar 29 '12 at 22:12
  • @FritsvanCampen Assuming that the plain-text password is not needed... it might be needed in some cases, such as passing along to another service outside of a better unified model. (It would be wonderful if Kerberos was supported in everything but, alas, it is not.) –  Mar 29 '12 at 22:14
  • @MihirSingh, you could just store in a file somewhere or right in the source code .. if you don't have need for an elaborate user system there's no need for a database. My point is, for the challenge response a database is not needed, but for user management: probably. – Halcyon Mar 29 '12 at 22:16
  • @pst that sounds blasphemous to me, passwords should never be stored in plaintext ever. You could just pass the hashed password and the salt. Assuming the salting mechanism is similar on both systems this should work fine. If not .. meh – Halcyon Mar 29 '12 at 22:17
  • 1
    Let me clarify... Not only is the password never stored in the database, it is also never stored anywhere on the server. The script simply examines the password, it doesn't save or store it anywhere. – citruspi Mar 29 '12 at 22:22
  • I'm knew to encryption and stuff, so just tell me... Would it work if I encrypted it using AES in obj-c and then decrypted it in PHP? – citruspi Mar 29 '12 at 22:23
  • 1
    If the password is never stored anywhere, then how do you know it's correct? ._. Using AES works, it uses a different cryptgraphic method (public-private key, which is more similar to HTTPS) – Halcyon Mar 29 '12 at 22:25
  • The problem with this solution is that you can only verify that the user knows the password. It doesn't protect the integrity of the request from, say, a man in the middle. – erickson Mar 29 '12 at 22:26
  • True, HTTPS does protect against that (or is supposed to anyway, search for "Moxio Marlinspike" :P ). – Halcyon Mar 29 '12 at 22:27
  • AES is a symmetric algorithm. It won't work here, and neither will a public key algorithm because the client doesn't have any root certificates that can verify the integrity of the public encryption key. – erickson Mar 29 '12 at 22:27
  • 1
    Mr. van Campen, it does not matter if the password is correct or not; there is no user base. I'm simply analyzing the string, not comparing it to a database of users. – citruspi Mar 29 '12 at 22:29
7

Reconsider not using HTTPS. HTTPS a good defense against a number of attacks.

There usually isn't a reason to transmit a password. By transmitting passwords, you are sending valuable data and their is extra risk associated with it.

Usually you hash the password and submit the hash. On the server side, you compare the hashes, if they match, great.

Obviously with this approach, the hash is important, and you have to secure against a replay attack. You could have your server generate a crypto-secure one-time use salt, pass that to the client, salt and hash the password, and compare the hashes serverside.

You also need to guard against a reverse hash attack on password. IE, I have a hash, and I can compare it to a bunch of pre-generated hashes to find the original password.

Alan
  • 45,915
  • 17
  • 113
  • 134
  • I gave a +1 simply for the opening line. The other bits are "meh" (okay "good advice") but don't pertain to this question. –  Mar 29 '12 at 22:11
  • I would be happy to use HTTPS, but I can't afford a certificate. – citruspi Mar 29 '12 at 22:16
  • 2
    You can use a self-signed cert for HTTPS if you own both the client and the server. – Alan Mar 29 '12 at 22:20
  • If you trim your answer to just the first line I'll give you an upvote too. The rest is too vague. – Halcyon Mar 29 '12 at 22:20
  • 1
    The problem with self-signing is that you have no authority that guarantees the certificate is correct and valid, and it's not something you could have a customer work with, too unprofessional. – Halcyon Mar 29 '12 at 22:23
  • Typically the client enforces that the certificate chain validates up to a trusted RootCA. This is done when you have an untrusted 2nd party. By both parties having trusted 3rd party, they can establish trust to each other. Since you wrote the client, and you are sending data to a server you own, you can forgo the validation of the cert up to a root-ca. This is less ideal, as an attacker could get access to your cert and spoof your identity and you couldn't revoke the cert. But...for your use, self-signed certs should be okay. However, I am not a security expert and this is free advice :) – Alan Mar 29 '12 at 22:26
  • But either way, the user would never know if the certificate is valid, right? Because they would see the iPhone user interface, and I don't plan on tainting the interface with some seal from a security company... But I understand what you're saying Mr. van Campen. In all honesty, although most users wouldn't realize that their password was not secure if I did not encrypt it, I just want to make an effort to secure the application. – citruspi Mar 29 '12 at 22:27
  • @FritsvanCampen Agreed. I added a lengthy comment on the downside. If you have a customer, the cost of a valid trusted cert should be baked into the contract and it should be moot. – Alan Mar 29 '12 at 22:27
  • @MihirSingh That's not a reason not to employ proper security however. It's pretty easy to run an iphone app through fiddler and watch HTTP requests. – Alan Mar 29 '12 at 22:29
  • @Alan, precisely. I know that sniffers can collect all the information passed through a network, which is why I am making an effort to secure the application. – citruspi Mar 29 '12 at 22:32
3

You could encrypt at the device and decrypt at the server, but if the data going across the wire is sensitive enough to warrant that much work, then IMHO, I believe you're better off just using https. It's tried, true, and established.

It's not perfect, mind you, and there have been successful attacks against older versions of it, but it is a heck of a lot better than "rolling your own" method of security.

Say your key gets compromized, for example: If you're using https with a cert from a trusted authority, then you just buy a new cert. HTe deveice, if it trusts the authority, will accept the new certificate. If you go your own route on it, then you have to update the keys not only on your web server, but at the client as well. No way would I want that sort of headache.

I'm not saying that the challenge is insurmountable. I am saying it may not be worth the effort when tools already exist.

David
  • 72,686
  • 18
  • 132
  • 173
  • Even if you are using HTTPS you really shouldn't pass credentials across the wire. – Alan Mar 29 '12 at 22:09
  • @Alan Good luck changing your password on a server in that case ;-) (In which case it's *much better* to send the plaintext on the wire and let the server do the hashing/management.) –  Mar 29 '12 at 22:10
  • Yes good point, but in general I like to employ the defense in depth strategy. If you don't have the change password remotely scenario, then avoid xmitting the password :) – Alan Mar 29 '12 at 22:19