How to send password securely via HTTP using Javascript in absence of HTTPS?

SecurityHttpHashPassword ProtectionHmac

Security Problem Overview


The very basic issue all developers face: Whenever user submits the form, the password is sent via network and it must be protected. The site I develop for doesn't have HTTPS. Neither does the owner want to buy a SSL certificate, nor is he interested in a self-signed one. So I want to protect the password sent via HTTP using Javascript when submitting form.

To eager downvoters: https://stackoverflow.com/questions/1582894/how-to-send-password-securely-over-http DOES NOT give any sensible solution and I am in another situation.

If I use MD5, one can reverse that password string. What about nonce/HMAC? Any available Javascript library for that? Or do you have any suggestion/hint to tackle? Thanks in advance!

Security Solutions


Solution 1 - Security

There is no way to send a password securely that the user can verify without SSL.

Sure, you can write some JavaScript that will make a password secure for over-the-wire transmission through hashing or public-key-encryption. But how can the user be sure that the JavaScript itself has not been tampered with by a man-in-the-middle before it reached them, to send the password to an attacker instead of the site, or even just compromise the security of the algorithm? The only way would be for them to be expert programmers and have them inspect every line of your page and script to ensure it was kosher before typing the password. That is not a realistic scenario.

If you want passwords to be safe from man-in-the-middle attacks, you must buy an SSL cert. There is no other way. Get used to it.

> If I use MD5, one can reverse that password string.

No... not trivially at least. Whilst MD5 has attacks against it, it's a hashing algorithm and thus unreversable. You would have to brute-force it.

But again, a man-in-the-middle attacker doesn't need to look at your MD5s. He can simply sabotage the JavaScript you send the user to make the MD5s.

Solution 2 - Security

The solution here is to not send the password at all. Use challenge/response.

In the original form include a large block of random text along with a key. Store the original random text in the session based on key on the server. When the client submits the form, use JS to hash the random text and password together. Then send the username, key, and hashed random text to the server. DO NOT send the password. On the server, use the key to lookup the original random text, perform the same hashing operation with the stored password. If the server-hashed value matches the client hashed value, then you know the client entered the right password without ever sending the password to the server.

Whether the password is right or not, expire the key and random text so each are one-time-use.

Solution 3 - Security

If you REALLY want to deep-dive into this, look at the Diffie-Hellman key exchange which was created to "allow two parties that have no prior knowledge of each other to jointly establish a shared secret key over an insecure communications channel"

I'm not a cryptography expert though, so I don't fully know if it's really secure if an attacker has both the Client (JavaScript source code) and the transport mechanism (Packet sniffer)

Solution 4 - Security

You can use a javascript RSA implementation to encrypt the password before sending. (Here is an example of RSA In Javascript.)

But I believe both this one and using a hash function will be vulnerable to replay attacks. So, be careful.

Solution 5 - Security

Unfortunately there will be no way to ensure security of a non-encrypted request. Anyone with access to your javascript will simply be able to reverse engineer it/tamper with it and anyone with a packet sniffer will be able to watch the unencrypted traffic. These two facts together mean:

No SSL? No security.

Solution 6 - Security

Any transmission that you have will be in the clear; that is, without SSL your critical information will be exposed. It is worth discussing that point with the site Owner. In other words, it's best to take necessary measure to fortify your data transmission, and SSL is one the basic, cheap steps you can take.

Solution 7 - Security

i don't think the issue here is the technology, but how you explain the importance of SSL. Provide them with reliable reading materials, i'm sure there are plenty over the web.

Solution 8 - Security

The solution requires the client to be able to encrypt the password using a secret encryption key known only to the client and the server.

SSL accomplishes this by requiring both the server and the client web browser to have their own asymmetric public/private keypair, which they use to encrypt and transmit a random session key between them. The rest of the conversation then uses that secure session key.

So you're asking how to solve the same problem as SSL without the benefit of having a secret key that is known only to the client and server. I'm no expert, but it looks like this can't be done, or at least not easily.

Solution 9 - Security

If you don't have access to SSL, MD5 should be adequate to prevent accidental discovery of passwords (such as in a network log file or something). Anything else would be a waste of time. Just make sure the app doesn't give access to sensitive information (ie, credit card numbers, medical history, etc).

Like others commenters have suggested, a serious attacker will be able to break any type of security on the page. Even SSL is a small barrier since most users use easy-to-guess passwords, re-use the same passwords everywhere, will give their password to anybody that asks, or can be tricked into giving up their password by a copied page or "tech support" phone call.

Solution 10 - Security

-- English -- i think in something, but i don't know if it could be really secure. If you can put your form in a php file, then you can create an algoritm for create a string based in time or in something else, and then put this string in your html.

When the user type a password in a password input field, when you debug it you canot see the value typed by user, so before send the information via post or get, you can use the password user as a hint to encrypt the encrypted string previosly generated, and then, just sent it insted of the password typed by user.

In this way, the attackers dont have all inside the js code, so they will need discover the algoritm that you create to decrypt it.

This is just an idea, so if you can tell me how this can not be safe, I would appreciate it.

-- Spanish -- Se me acaba de ocurrir algo que puede servir, pero no se si realmente sea algo seguro. Por medio de php puedes generar un algoritmo que cree un string en base al timestamp o algo más, y después colocar esta cadena en el html.

Note que cuando alguien escribe una contraseña en un campo input tipo password, con un debug no se puede ver el valor que tecleo el usuario (no se si exista manera pero no quise investigar más), asi que podemos utilizar la contraseña que el usuario escribió como palabra clave para encriptar la cadena de texto que previamente habiamos generado con php, por medio de un algoritmo en JS. Sería algo así como encriptar lo encriptado. Posteriormente lo que estariamos enviado no sería la contraseña tecleada, si no esta última cadena resultante.

Buscando un contra, lo único que se me ocurra es que el atacante tendrá que dedicarle mucho tiempo para tratar de encontrar el agoritmo que creamos por medio de php y poder decriptar la cadena final, o tendrá que hackear el servidor para acceder al php y obtener el algoritmo.

Esto es solo una idea, por lo que si pueden decirme como esto puede no ser seguro, se los agradecería.

Solution 11 - Security

As mentioned, none of this is secure against server spoofing, as that requires an ability to trust the client-side Javascript. But if we're sure that the server can't be spoofed (signed cert, hash signing immune to length-extension, etc.) but not that the connection is immune to eavesdroppers, here's how I'd implement it.

I think the most secure way is, instead of storing H(password), where H is your hash function of choice, store g^H(password) i.e. use the password as the private key for Diffie-Hellman key exchange. (You should also probably use a random g for different users, too--it becomes your salt.) Then to verify, you generate a nonce b, send the user g^b, and compute (g^H(password))^b. The user does not need to know g--they need only compute (g^b)^H(password) = (g^H(password))^b. Now you have a number that both parties know iff the user entered the right password, and constructing a challenge-response zero-knowledge proof based on knowing the correct number is trivial, while the random number used as the server's "private key" makes the approach immune to replay attacks.

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
QuestionVietView Question on Stackoverflow
Solution 1 - SecuritybobinceView Answer on Stackoverflow
Solution 2 - SecuritySamuel NeffView Answer on Stackoverflow
Solution 3 - SecurityMichael StumView Answer on Stackoverflow
Solution 4 - SecuritySzere DyeriView Answer on Stackoverflow
Solution 5 - SecurityrfundukView Answer on Stackoverflow
Solution 6 - SecurityDavid RobbinsView Answer on Stackoverflow
Solution 7 - SecurityMartin OngtangcoView Answer on Stackoverflow
Solution 8 - SecurityDavid R TribbleView Answer on Stackoverflow
Solution 9 - SecurityBrianView Answer on Stackoverflow
Solution 10 - SecurityeduardossmxView Answer on Stackoverflow
Solution 11 - SecurityNXTanglView Answer on Stackoverflow