9

Without any common JS libraries, how can I hash a password before sending it?

<form>
    <input type="password" id="pwd" name="password" />
    <input onclick="
var val = document.getElementById('pwd').value;
document.getElementById('pwd').value(sha512(val));"
     type="submit">
</form>

That would somehow be my naive way to do it (with sha512 being a function defined somewhere to create the sha512 value)

Though it obviously does not seem to work. Why? How do I do this right and simple?

salbeira
  • 2,375
  • 5
  • 26
  • 40
  • 6
    By design you can not get a value out of a password field using client side javascript. Otherwise an XSS vulnerability would be disastrous. If you wish to forgo this protection then you will have to roll out your own password input field. As others have pointed, you need a very good reason to want to hash passwords client side. I presume you are also salting and hashing them on the server, but the client side hash will weaken your cryptography (in theory). – Jozef Legény Jan 22 '16 at 17:51
  • That is actually very useful to know. – salbeira Jan 22 '16 at 18:07
  • 13
    Erm... that's not true, you can perfectly well read an ``—eg https://jsfiddle.net/64jo0tyr/. XSS vulnerabilities are indeed disastrous. – bobince Jan 23 '16 at 00:09
  • 1
    @bobince you are correct. I wonder why I was under that impression. – Jozef Legény Jan 23 '16 at 08:03
  • FWIW the type="password" attribute is a presentational thing only, to prevent people from looking over your shoulder at the password you're typing. It is functionally the same as type="text" – user2087941 Jul 14 '22 at 05:59

7 Answers7

9

Lots of issues here... like hashes without a salt can be rainbow tabled. If you send and then store the hash they make... its like storing a cleartext password now. If the client salts and hashes and then the server salts and hashes it... how do you ensure they can hash again with the correct salt. Bottom line, use a secure connection and then salt/hash on the server.

Goblinlord
  • 3,290
  • 1
  • 20
  • 24
  • 1
    It's just learning how to do what I describe above, using a secure connection comes right after that. – salbeira Jan 22 '16 at 17:52
  • 2
    I think you are missing the point... doing this... well there is no point to learning it because in practice it makes no sense. If you send the hash... and store the hash... then you are essentially storing the cleartext password. The whole point to hashing the password is so someone can't read your DB record and then use the password it contains to gain access later. If you only check the hash against the hash... you have gained nothing and made it less secure. – Goblinlord Jan 22 '16 at 17:54
  • You are right. As of now I do not care if someone uses someone's identity to access whatever I do. So the only thing I try to accomplish with that is having someone snooping the package not being able to get the plain text password out of the connection, securing the user that will DEFINETLY USE A PASSWORD MORE THAN ONCE (cause that's what people do) having his password exposed on the way to the server. – salbeira Jan 22 '16 at 17:59
  • 1
    Please google rainbow tables... and note you are not salting this hash and there is no way you can consistently salt this hash without reusing your salt (and likely making your salt known to anyone reading your js). You are trying to make something secure without understanding what you are actually doing. – Goblinlord Jan 22 '16 at 18:01
  • *sigh* It's not like I am using MD5 and I still see your point but you also still think I would do what I do in any kind of productive system. I do this right now JUST to tinker around and get to know what I am working with. – salbeira Jan 22 '16 at 18:05
  • md5... sha512... rainbow tables with no salt are common these days... people create them these days regardless of the algorithm. Unsalted hashes are likely much less secure than you assume they are. Anyways, it looks like someone else here has probably answered your question sufficiently. – Goblinlord Jan 22 '16 at 18:07
9

I propose you to use jsSHA public sw and put outside your js:

function mySubmit(obj) {
  var pwdObj = document.getElementById('pwd');
  var hashObj = new jsSHA("SHA-512", "TEXT", {numRounds: 1});
  hashObj.update(pwdObj.value);
  var hash = hashObj.getHash("HEX");
  pwdObj.value = hash;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jsSHA/2.0.2/sha.js"></script>

<form>
    <input type="password" id="pwd" name="password" />
    <input onclick="mySubmit(this)" type="submit">
</form>
gaetanoM
  • 41,594
  • 6
  • 42
  • 61
6

Hashing the password on the client before send it to the server is a complete nonsense and shouldn't be done.

Don't take my word for granted and let's find out why:

The client sends the hashed password to the server. From an attacker point of view, the hash is all it's needed to gain access to the login (i.e. the attacker spoofs the hash in transit and uses it to gain access to the server).

That's exactly the same scenario as if the client was sending the plain text password. The attacker would spoof the clear text password and use it to login.

So now it's clear that hashing the password on the client side doesn't mitigate the threat scenario in which an attacker is listening for your password in transit. This threat scenario is mitigated by using a secure connection (e.g. HTTPS).

Hashing the password is still important though: the server should hash the password and compare it to the hashed version stored in the database. Salting is also required, to mitigate rainbow table attacks

Gianluca Ghettini
  • 11,129
  • 19
  • 93
  • 159
  • 1
    Though this question is old, I think my thought process was rather that if the attacker listens for the password and it is sent in plain text, then the attacker would also know the password the victim uses for other services. If only the hash is ever sent, then the attacker would maybe be able to compromise this single service, but not all services the user accesses. This, of course is mitigated by using no password twice, using a manager for password generation etc., but we both know the world doesn't work that way ... – salbeira Oct 16 '20 at 10:51
  • @salbeira Also consider that in this day and age, with all the modern GPUs out there, having the hash is almost equivalent to having the plain text password. Salting is what really prevents reversing an hashed password (i.e. the attacker cannot use prebuilt rainbow tables) – Gianluca Ghettini Oct 16 '20 at 15:02
  • @salbeira If you're worried about attackers intercepting the data being sent over the wire, then you should be using HTTPS exclusively. See Troy Hunt's blog if you need more reasons: [Here's why your static website needs HTTPS](https://www.troyhunt.com/heres-why-your-static-website-needs-https/) – Richard Deeming Nov 10 '21 at 12:02
  • 4
    Client side hashing prevents server admins from being able to see clear text passwords. It should be hashed server side also. – Jonathan Jul 26 '22 at 15:39
  • "*From an attacker point of view, the hash is all it's needed to gain access to the login*" The author never said that. One could suggest "do another quick hash on the server after doing the heavy hash on the client", but you chose to just not answer the question. "*That's exactly the same scenario as if the client was sending the plain text password.*" Are you familiar with haveibeenpwned and similar? The credential stuffing technique? Leaking plain text passwords to the server is very different from sending it a hash. Please don't give out security advice. – Luc Aug 08 '23 at 21:26
4

document.getElementById('pwd').value(sha512(val));

You meant value = sha512(val).

This would have given you an exception with some helpful error message (eg value is not a function), so keep the JS console open so you can see the errors.

Note that client-side password hashing is usually an antipattern, and certainly not a workable substitute for proper SSL.

bobince
  • 528,062
  • 107
  • 651
  • 834
1

I had success by listening to the submit event, then cancelling the submit, modify the password field with the hash, and then trigger the submit again.

I use the subtle crypto API to calculate the hash. This is built in in the browser, but getting strings in and out is some work.

<script>
    const form = document.querySelector("form");
    form.addEventListener("submit", function (e) {
        e.preventDefault();
        const passwordInput = this.querySelector("input[type=password]");
        crypto.subtle.digest("SHA-384", new TextEncoder().encode(passwordInput.value)).then(function (hashBuffer) {
            const hashArray = Array.from(new Uint8Array(hashBuffer));
            const hashHex = hashArray.map((b) => b.toString(16).padStart(2, '0')).join('');
            passwordInput.value = hashHex;
            form.submit();
        });
    });
</script>
Sjoerd
  • 74,049
  • 16
  • 131
  • 175
0

I don't think that it is a good idea to hash password in clientside. But you can use CryptoJS

https://code.google.com/p/crypto-js/

<script src="http://crypto-js.googlecode.com/svn/tags/3.1.2/build/rollups/sha512.js"></script>
<script>
    var hash = CryptoJS.SHA512("Message");
</script>
Tom
  • 43,583
  • 4
  • 41
  • 61
Ruben Yeghikyan
  • 497
  • 2
  • 6
  • 19
  • That still doesn't fix the problem that the actual on-click function does not work. – salbeira Jan 22 '16 at 17:51
  • Sorry for this ultra noob question. How do I get the original password after it's been hashed using CryptoJS.SHA512? – CodeSadhu Apr 02 '21 at 13:59
  • @CodeSadhu using Rainbow Table, (dictionary). About the question of @salbeira: yes!, is AGOOD idea transform in HASH the password from side client and ever is ``mandatory`` use `password_hash(string_hashed_by_JS, PASSWORD_DEFAULT)` in side server. – VyR Apr 03 '21 at 13:42
-1

You can also use this hash function which is very fast. In the example below you will send to the server the hash of the password. Remember that the hash generated it is a number so just convert it to string if you need it as string.

var hashStr = String(hashCode(pass));

const hashCode = s =>
    s.split('').reduce((a, b) => {
      a = (a << 5) - a + b.charCodeAt(0);
      return a & a;
    }, 0);
    
    
function submitMe() {
  var pass = document.getElementById('userPwd').value;
  var enc = hashCode(pass);
  document.getElementById('userPwd').value = enc;
  console.log(enc);   //for debug
  console.log(document.getElementById('userPwd').value);   // for debug
}
<form action='/login' method='POST'>  
    <input type='password' id='userPwd' name='pwd' min='8' max='16'>
    <input type='submit' value='SUBMIT' onclick='submitMe()'>  
</form>
Pietro
  • 127
  • 6
  • 1
    This is **not a cryptographic hash function**. While using SHA512 client-side just doesn't help security, your approach actively harms it, by reducing the total entropy to (probably less than) four bytes. **Do not** use this approach in production. – Tau Dec 18 '21 at 07:56
  • Thank you for pointed that out. I just need to send hashed password to the server in case someone was doing packet sniffing and I could not use MD5. So I had found this solution in this post https://stackoverflow.com/questions/7616461/generate-a-hash-from-string-in-javascript – Pietro Dec 23 '21 at 07:44
  • My server can be only http (it is a small IoT device that does not have https). This is actually where I got that hash code from https://stackoverflow.com/questions/64873113/how-to-hide-credentials-in-client-side-javascript-application I thought this hash was one way only. If you have found a better solution please share. – Pietro Dec 23 '21 at 08:02
  • Well, someone doing packet sniffing could just as well sniff out the hashed password and replay that. If you have direct access to both the client and the server (i.e. key exchange is not a problem), just use any decent encryption library (of which there are probably numerous ones for Javascript). Otherwise, there's really no way around HTTPS. – Tau Dec 28 '21 at 15:49