How to send password securely over HTTP?

HttpSecurityEncryptionTextPasswords

Http Problem Overview


If on a login screen user submits a form with their username and password, the password is sent in plain text (even with POST, correct me if I am wrong).

What is the right way to protect the user and his password against the third party who might be eavesdropping on the communication data?

I am aware that HTTPS is a solution to the problem, but is there any way to ensure at least some level of security using the standard HTTP protocol (POST request)? (perhaps using javascript in some way)

What I was about was a page - that is a PHP-generated login page, which is of course sent to users in HTTP GET request as an HTML file. There is no (@Jeremy Powel) connection established between the server and the client so I can't create such a handshaking protocol. And I want the complete process to be transparent to the user - he wants to submit a password, not deal with cryptography.

Http Solutions


Solution 1 - Http

Using HTTP with SSL will make your life much easier and you can rest at ease. Very smart people (smarter than me at least!) have scrutinized this method of confidential communication for years.

Solution 2 - Http

Secure authentication is a broad topic. In a nutshell, as @jeremy-powell mentioned, always favour sending credentials over HTTPS instead of HTTP. It will take away a lot of security related headaches.

TSL/SSL certificates are pretty cheap these days. In fact if you don't want to spend money at all there is a free letsencrypt.org - automated Certificate Authority.

You can go one step further and use caddyserver.com which calls letsencrypt in the background.

Now, once we got HTTPS out of the way...

You shouldn't send login and password via POST payload or GET parameters. Use an Authorization header (Basic access authentication scheme) instead, which is constructed as follows:

> - The username and password are combined into a string separated by a > colon, e.g.: username:password
> - The resulting string is encoded using > the RFC2045-MIME variant of Base64, except not limited to 76 > char/line. > - The authorization method and a space i.e. "Basic " is then > put before the encoded string.
> > source: Wikipedia: Authorization header

It might seem a bit complicated, but it is not. There are plenty good libraries out there that will provide this functionality for you out of the box.

There are a few good reasons you should use an Authorization header

  1. It is a standard
  2. It is simple (after you learn how to use them)
  3. It will allow you to login at the URL level, like this: https://user:[email protected]/login (Chrome, for example will automatically convert it into Authorization header)

IMPORTANT:

  • As pointed out by @zaph in his comment below, sending sensitive info as GET query is not good idea as it will most likely end up in server logs.
  • The Authorization header value is traditionally a base64-encoded username/password. Base64 is not encryption. The original value can be obtained by an on-path attacked using a simple base64-decode.

enter image description here

Solution 3 - Http

You can use a challenge response scheme. Say the client and server both know a secret S. Then the server can be sure that the client knows the password (without giving it away) by:

  1. Server sends a random number, R, to client.
  2. Client sends H(R,S) back to the server (where H is a cryptographic hash function, like SHA-256)
  3. Server computes H(R,S) and compares it to the client's response. If they match, the server knows the client knows the password.

Edit:

There is an issue here with the freshness of R and the fact that HTTP is stateless. This can be handled by having the server create a secret, call it Q, that only the server knows. Then the protocol goes like this:

  1. Server generates random number R. It then sends to the client H(R,Q) (which cannot be forged by the client).
  2. Client sends R, H(R,Q), and computes H(R,S) and sends all of it back to the server (where H is a cryptographic hash function, like SHA-256)
  3. Server computes H(R,S) and compares it to the client's response. Then it takes R and computes (again) H(R,Q). If the client's version of H(R,Q) and H(R,S) match the server's re-computation, the server deems the client authenticated.

To note, since H(R,Q) cannot be forged by the client, H(R,Q) acts as a cookie (and could therefore be implemented actually as a cookie).

Another Edit:

The previous edit to the protocol is incorrect as anyone who has observed H(R,Q) seems to be able to replay it with the correct hash. The server has to remember which R's are no longer fresh. I'm CW'ing this answer so you guys can edit away at this and work out something good.

Solution 4 - Http

If your webhost allows it, or you will need to deal with sensitive data, then use HTTPS, period. (It's often required by the law afaik).

Otherwise if you want to do something over HTTP. I would do something like this.

  1. The server embeds its public key into the login page.
  2. The client populates the login form and clicks submit.
  3. An AJAX request gets the current timestamp from the server.
  4. Client side script concatenates the credentials, the timestamp and a salt (hashed from analog data eg. mouse movements, key press events), encrypts it using the public key.
  5. Submits the resulting hash.
  6. Server decrypts the hash
  7. Checks if the timestamp is recent enough (allows a short 5-10 second window only). Rejects the login if the timestamp is too old.
  8. Stores the hash for 20 seconds. Rejects the same hash for login during this interval.
  9. Authenticates the user.

So this way the password is protected and the same authentication hash cannot be replayed.

About the security of the session token. That's a bit harder. But it's possible to make reusing a stolen session token a bit harder.

  1. The server sets an extra session cookie which contains a random string.
  2. The browser sends back this cookie on the next request.
  3. The server checks the value in the cookie, if it's different then it destroys the session, otherwise all is okay.
  4. The server sets the cookie again with different text.

So if the session token got stolen, and a request is sent up by someone else, then on the original user's next request the session will be destroyed. So if the user actively browsing the site, clicking on links often, then the thief won't go far with the stolen token. This scheme can be fortified by requiring another authentication for the sensitive operations (like account deletion).

EDIT: Please note this doesn't prevent MITM attacks if the attacker sets up their own page with a different public key and proxies requests to the server. To protect against this the public key must be pinned in the browser's local storage or within the app to detect these kind of tricks.

About the implementation: RSA is probably to most known algorithm, but it's quite slow for long keys. I don't know how fast a PHP or Javascript implementation of would be. But probably there are a faster algorithms.

Solution 5 - Http

You can use http://en.wikipedia.org/wiki/Secure_Remote_Password_protocol">SRP</a> to use secure passwords over an insecure channel. The advantage is that even if an attacker sniffs the traffic, or compromises the server, they can't use the passwords on a different server. https://github.com/alax/jsrp is a javascript library that supports secure passwords over HTTP in the browser, or server side (via node).

Solution 6 - Http

I would use a server-side and client-side Diffie-Hellman key exchange system with AJAX or multiple form submits(I recommend the former), although I don't see any good implementations thereof on the internet. Remember that a JS library can always be corrupted or changed by MITM. Local storage can be used to help combat this, to an extent.

Solution 7 - Http

HTTPS is so powerful because it uses asymmetric cryptography. This type of cryptography not only allows you to create an encrypted tunnel but you can verify that you are talking to the right person, and not a hacker.

Here is Java source code which uses the asymmetric cipher RSA (used by PGP) to communicate: http://www.hushmail.com/services/downloads/

Solution 8 - Http

you can use ssl for your host there is free project for ssl like letsencrypt https://letsencrypt.org/

Solution 9 - Http

Using https sounds best option here (certificates are not that expensive nowadays). However if http is a requirement, you may use some encription - encript it on server side and decript in users browser (send key separately).

We have used that while implementing safevia.net - encription is done on clients (sender/receiver) sides, so users data are not available on network nor server layer.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionKornelije PetakView Question on Stackoverflow
Solution 1 - HttpJeremy PowellView Answer on Stackoverflow
Solution 2 - HttpFullStackForgerView Answer on Stackoverflow
Solution 3 - HttpJeremy PowellView Answer on Stackoverflow
Solution 4 - HttpCalmariusView Answer on Stackoverflow
Solution 5 - HttpBrian MintonView Answer on Stackoverflow
Solution 6 - HttpnanofaradView Answer on Stackoverflow
Solution 7 - HttprookView Answer on Stackoverflow
Solution 8 - Httpmk990View Answer on Stackoverflow
Solution 9 - HttpparvuselephantusView Answer on Stackoverflow