When I want to put a login system in place, I always compare the MD5 of the given password with its value in the users table on the server side.
However, a friend of mine told me that a "clear" password could be sniffed by a network software.
So my question is: is it a good idea to hash the password on the client side? Is it better than hashing it on the server side?
Basically, your friend is right. But simply hashing the password on the client side is only just better than submitting it as plain text to the server. Someone, who can listen for your plain text passwords is certainly also able to listen for hashed passwords, and use these captured hashes him/herself to authenticate against your server.
For this matter, more secure authentication protocols usually jump through a number of hoops in order to make sure, that such a replay attack cannot work, usually, by allowing the client to select a bunch of random bits, which are hashed along with the password, and also submitted in the clear to the server.
On the server:
generate a few bits of random
send these bits (in clear text) to the client
On the client:
generate a few random bits
concatenate password, the server's random bits and the client random bits
generate hash of the above
submit random bits(in clear text) and hash to the server
As the server knows its own random information as well as the client's random bits (it got them as clear text), it can perform essentially the same transformation. This protocol makes sure, that nobody listening in this conversation can use the information later to authenticate falsely using the information recorded (unless a very weak algorithm was used...), as long as both parties generate different "noise bits" each time, the hand shake is performed.
Edit All of this is error prone and tedious and somewhat hard to get right (read: secure). If ever possible, consider using authentication protocol implementations already written by knowledgeable people (unlike me! The above is only from memory of a book I read some time ago.) You really don't want to write this yourself usually.
First of all, this does NOT improve the security of your application (assuming it is a web app).
Use SSL (Or actually TLS, which is commonly called SSL). It is free and easy to set up with Certbot.
The why to this is simple. TLS solves a problem (when used with a certificate from a certificate authority, not self signed) that is quite big in cryptography: How do I know the server I am talking to is the server I think I am talking to? TLS Certificates are a way of saying: "Me, the certificate authority, trusted by your browser, certifies that the website at [url] has this public key, with a corresponding private key, which (private key) only the server knows, look I signed my signature all over the document, if anyone altered it you can see".
Without TLS, any encryption becomes pointless, because if I sit next to you in a coffeeshop, I can make your laptop/smartphone think I am the server and MiTM (Man in The Middle) you. With TLS, your laptop/smartphone will scream "UNTRUSTED CONNECTION", because I don't have a certificate authority signed certificate that matches your site. (Encryption vs. Authentication).
Disclaimer: users tend to click right through these warnings: "Untrusted connection? What? I just want my pictures of kittens! Add Exception Click Confirm Click YAY! Kittens!"
However, if you really do not want to use a certificate, still DO implement client side Javascript hashing (and use the Stanford library (SJCL) for that, NEVER IMPLEMENT CRYPTO YOURSELF).
Why? Password reuse! I can steal your session cookie (which allows me to pretend to your server that I am you) without HTTPS easily (see Firesheep). However if you add Javascript to your login page which, before sending, hashes your password (use SHA256, or even better, use SHA256, send them a public key you generated and then encrypt hashed the password with that, you cannot use a salt with this), and then sends the hashed/encrypted password to the server. REHASH the hash on your server with a salt and compare that to what is stored in your database (store the password like this:
(SHA256(SHA256(password)+salt))
(save the salt as plaintext in the database as well)). And send your password like this:
RSA_With_Public_Key(SHA256(password))
and check your password like this:
if SHA256(RSA_With_Private_Key(SHA256(sent_password))+salt_for_username) == stored_pass: login = ok
Because, IF someone is sniffing your client, they will be able to login as your client (session hijacking) but they will NEVER see the plaintext password (unless they alter your Javascript. However, a Starbucks hacker will probably not know how or be interested in this.) So they will gain access to your webapp, but not to their email/Facebook/etc. (for which your users will likely use the same password). (The email address will either be their login name or will be found in their profile/settings on your web app).
Actually I disagree that client side hashing is more secure in this case. I think it's less secure.
The entire point of storing a hash of the password in your database as opposed to the real password (or even an encrypted password) is that it is mathematically impossible to obtain the original password from a hash (although it is theoretically possible to obtain a colliding hash input, the difficulty of which depends on the security strength of the hashing algorithm). The possible attack vector here is that if a potential attacker somehow compromised your password storage database, he/she still would not be able to obtain the original passwords of your users.
If your authentication mechanism sends a hash of the password, then in the "security breach" scenario (i.e. attacker somehow got a copy of your password database), the attacker does not need to know the real password - they just send the hashed password that they obtained from the breach and hey presto, they have access to that user's account. This completely defeats the point of storing a hashed password in the first place!
The really secure way to do it is to send the client a one-time public key for them to encrypt the password, then you decrypt and re-hash it on the server-side.
By the way, this kind of question will probably get more expert responses over on Security StackExchange.
You're likely OK not to worry about this - as Dirk mentions even if you hash the passwords a malicious user could be on a network and see the hash get sent, and could simply send the same hash themselves.
It is slightly better, in that it prevents the malicious user from knowing what the password is, but since they can still log in (or potentially reconstruct the original password), that's not that helpful.
In general, if you're concerned about the safety of your user's passwords and data (and you should be!), you'll want to use a secure SSL server. If this isn't a concern for you for whatever reason you might as well not bother with hashing; it's just security through obscurity.
Edit Aug 2014: Google is pushing more and more strongly for websites to switch to HTTPS everywhere, because securing the communication itself is the only way to prevent network sniffing attacks. Attempts at obfuscating the data transmitted will only hinder, not stop, a dedicated attacker, and can give developers a dangerous false sense of security.
Recently both GitHub and Twitter announced that passwords where stored in internal logs. I've had this happen inadvertently in bug reports and other logs that found their way into splunk etc. For twitter if Trump's password was in there log it could be a big deal for an admin to "see", for other sites probably not as big of a deal as the administrators wouldn't have much use for it. Regardless as admins we don't like seeing the passwords do we.
So the question is really if the hashing should happen client side for security, but how can we protect the password before it ultimately gets hashed and compared by the server side so it doesn't get logged somehow.
Encryption is not a bad idea because the developers at least have to jump through some hoops, and if you find that passwords got into logs you can just change the encryption key, destroy the original, and that data becomes useless. Better yet rotate the keys nightly and it could reduce the windows greatly.
You could also hash a hash in your user record. The leaked passwords would be hashed plain text passwords. The server would store a hashed version of the hash. Sure the hash becomes the password, but unless you've got a photographic memory you are not going to remember a 60 char bcyrpt. Salt with the username. If you could gather something about the user during the login process (while not exposing that the user record exists ) you can salt with that as well creating a more robust hash that couldn't be shared between sites. No man in the middle would be able to just cut and paste the captured hash between sites.
Combine with a cookie that doesn't get submitted back to the server and you might be onto something. On first request submit a cookie to the client with a key, then make sure that cookie doesn't make its way back to the login service so little chance of it being logged. Store the key in a session store, and then delete it right after login occurs or when session expired... this requires state for you JWT guys, but maybe just use a nosql service for it.
So down the road an admin comes across one of these hashed and encrypted passwords in splunk or a bug reporting tool. It should be useless to them as they can't find the encryption key anymore, and even if they did they then have to brute force a hash. In addition the end user didn't send anything plaintext along the line so any man in the middle at least has a harder time of it and you can't just hop to another site and login.
Note that keeping passwords secure against third parties parties is not all there is to it.
As soon as privacy is involved (and when ever is it not, these days?) you don't want to know the password. You can't abuse or leak what you don't have, so both you and your clients can sleep better if you never ever see their clear-text passwords.
Therefore, hashing/encrypting client-side makes sense.
It depends, you can use client side hashing, but server side salt will not be possible.
have a look at the link
Password encryption at client side
This idea of client side hashing is to protect the user, not your site. As mentioned many times already, plain text or hashed passwords both have access to your site equally. You don't get a security benefit.
But your users actual, plain text, password should only be known by them. Knowing what they chose as a password is information that can be used against them on other sites and systems. You are being a customer-focused site by protecting them from having their password choice discovered by your server devs or by third parties.
I've been doing a lot of work on this recently, IRL there are two issues with client side hash / symmetric encryption with really kill the idea:
1. You have to get the salt back to the server SOMEHOW...and to encrypt it client side you'd need a password...which defeats the purpose.
2. You expose your hashing implementation (not a HUGE deal as most sites use one of 3 or 4 hashing algos) which makes the attack easier (as just need to try one rather than n).
What I eventually went to was asymmetric encryption on the client using OpenPGP.js or similar...
This relies on an imported or client side generated key on the client and the server sending it's public key. Only the client's public key may be sent back to the server.
This protects against MIM attacks and is as secure as the device (I currently store client's private key by default in localStore, it's a demo).
The MAJOR advantage of this is that I never have to have users data stored / even in memory unencrypted on my server / data store (and my server's private key is physically separate)
The basis of this was to provide people a way to communicate securely where HTTPS was restricted (e.g., Iran / N. Korea atc...) and also just a fun experiment.
I'm FAR from the first to think of this, http://www.mailvelope.com/ uses this
If someone can see the data in and out on your connection then authentication will not save you.
Instead I would do the following for super secret stuff.
Passwords prehashed on client side before sent to server.
(Server stores another hashed and salted value of that hash sent from the browser).
So a middle man attack could allow them to send the same hashed value to login as them, but the users password would not be known. This would stop them trying other services with the same credentials to login elsewhere.
Users data is encrypted on the browser side too.
Ah, so a middle man attack would get the encrypted data, but would not be able to decrypt it without the actual password used to login. (users password stored in the DOM on the browser when they logged in).
So the real user would see the decrypted contents but the middle man could not.
This also means any NSA or other agency would not be able to request you/company/hosting provider to decrypt this data as it would be impossible for them to do so as well.
Some small examples of both of these methods are on my blog
http://glynrob.com/javascript/client-side-hashing-and-encryption/
Consider this:-
Client sends request to server "I have a password to validate".
Server sends client a one-time only random string. R$
Client embeds the user's password in this string (based on any (variable) rules you wish to apply).
Client sends the string to the server and if password OK, server logs user in.
Should server receive another login request using R$, user is logged out and the account is frozen pending investigation.
Obviously all other (normal) security precautions would be taken.
The method that I have come up with is to use SHA-256 with multiple rounds and a random salt...
salt = generate random salt
hash = sha256(password)
for (i = 0 to rounds)
hash = sha256(hash + salt)
This encrypts the password in such a way that only the user knows what the password is. Both salt and hash are stored in the database. I have also implemented this on the client side using a server generated random string.
server_data = {
algorithm,
rounds,
salt,
string
}
hash = hash(server_data.algorithm, password)
for (i = 0 to server_data.rounds)
hash = hash(server_data.algorithm, hash + salt)
hash = hash(server_data.algorithm, hash + server_data.string)
In crypto class, we were taught that the attacker can know the algorithm, salt, rounds, etc.... But in this case, the actual hashed password is never sent. The server knows what the random string that it sent was, so the full hash is generated on the client, and the final piece is to hash that result with the random string. That's the result that's sent to the server. The result is effectively a one-time password that is useless on replay attacks. The user's password is never sent in the clear, and if the attacker gained the password hash, it would be useless to them because the server will not accept it in that form. The hacker MAY be able to compute a rainbow table for the salt and the number of rounds to try and brute force the password, but any sufficintly complex password using ASCII symbols 32-126 of at least 8 characters long will usually take a long time to crack...and that's for EACH password. The sites that I write for can have passwords up to 128 characters in length.
As for session hijacking, that risk can be reasonably mitigated by regenerating the session ID every 30 seconds or so. I also include a token that's embedded in the HTML of the page itself. On the server side, some of the client information such as the client's IP address and user agent string are hashed as well and stored in the user's session data.
So on each request, the server gets the cookie session ID and the token. The token is compared to what is in the session data. The other information such as the IP address and user agent are hashed and compared to what's in the session as well. If it all matches, then there's a very high probability that this is the real user and not an intruder.
The only way that I can see this happening is if the attacker has the embedded token, the same IP address, and the same user agent. It's all about probabilities. Besides, any time you are dealing with crypto, it can be hard to get right. So as others have said, don't do it yourself.
It's 2022 now. As hacker attacks are getting more sophisticated, luckily also have browser standards. The defacto transmission protocol is encrypted (https) and cross site scripting or replay attacks systematically are more difficult with content security policies and CORS.
I believe your time will be well spend familiarising yourself with these technologies.
I'm not a security expert and leave that in the hands of more capable engineers.
I need to make an authentication system for an express app I'm building. The client asked to have a password system that uses just a 4-digit pin. I have the code setup to save and hash the pin with the rest of the user info when creating a new user and the project is just an in-house server so it doesn't need to handle a ton of users.
My problem is signing the user back in. I'm using bycrypt to hash the password, but bycrypt generates a completely new hash for identical strings.
What I'm having trouble doing is fetching the user by doing a WHERE hash=hash SQL search. But that's not working because the hash is different every time even when the passwords are identical.
I could get all the users and iterate over all of them and use bycrypt's .compare method. But that won't work in the long run as the amount of users grows, and bycrypt is build to take a long time on cpu's to help prevent brute-force attacks.
I could also build my own hashing function. However, that would make it so I have to store a salt with each user to make each password unique. Then that brings up the same problem of not having the same hash for identical strings.
I know this is vague but I need some help thinking up a way to get the user by fetching it using the hashed password.
Just store the PIN as plain text. Using a hashing function on a 4 digit PIN does nothing but provide a false sense of security. Even an intentionally slow hashing function is easy to brute force if there are only 10,000 possible inputs.
What I'm having trouble doing is fetching the user by doing a WHERE hash=hash SQL search
Are you saying that you don't even know who the person claims to be, but are using the 4 digit pin as both the claim and the proof? It sounds like you building a system with only a pretense of security.
I want to implement an authentication system by following good practices, i want it as simple as possible and secured (im not going to implement some magic hashing function or something to feel a hero..) just wanting to use already known hash but not sure the right way of using it.
I read some articles on how Lastpass (a password management company) mange to handle their authentication and i loved their idea.So i wanted to implement my own authentication based on it.
Basically im creating an authentication key from the password on the client side (so the password is never sent as a plan text to the server).
that authentication key im sending to the server than do some hashing operations also in the server side and compare the result to the one inside the database.
On my client side:
auth_key = PBKDF2(SHA256, password+username, last_login_fe_salt, fe_rounds)
explanation - hashing password+username+last_login_fe_salt text fe_rounds times
last_login_fe_salt -> a random salt sent to the user once he/she input their username in text field -
To be honest, not sure how this last_login_fe_salt is efficent for the cryptography against Dictionary attacks but atleast two people having the same password will send different hashes on their network.
any hacker can get this data by asking from the server, i can add server side limitations (req/s if it makes some difference etc.. let me know what you think) also adding captcha might be a good idea. When a user logged in successfuly the server generates a new random string and saves in into the database.
*I didnt see any explanation which salt Lastpass uses on their client side hashing, they are using PBKDF2 algorithm that needs a salt parameter.
fe_rounds -> number of rounds given by the server when typing username -
its fixed for everybody and configurable by the server, also in articles i read about Lastpass they dont explain from where they receive the client side number of rounds...
so now we send auth_key as is to the server...
On my server side
now we are creating a new hash to compare the one inside the db.
Why another hash? if i understand correctly we bind the hash for server side data, like a combination of a password (that only the user knows) and server data.
db_auth=PBKDF2(SHA256, auth_key, user_be_salt, 100,000+user_configurable_rounds)
user_be_salt -> a random number that saved in db known only to the server and the ones who obtain the database, this changes on every successful login.
user_configurable_rounds -> number of iterations, every user can choose the amount of iterations (like in Lastpass) so attacker need also to guess the number or iterations?
I would be happy to hear what do you think about this authentication system, if its wrong than explain to me why and tell me what Lastpass do because i did not understand their entire authentication flow.
Most of what you're doing is useless from a security perspective. Lastpass has unusual security requirements -- don't treat them as a source of best practices.
If the client is responsible for hashing, and all of the parameters to that hashing are fixed, the hash effectively becomes the password. An attacker doesn't need to know the original password; they can simply pass the hash to the server.
Generally speaking, there is no way to verify a password over a network without either sending the password across the network (for traditional password authentication protocols), or having the server store the password in plaintext (for less commonly used protocols like SRP). Of the two, the former is preferable, as it's possible to secure the password in transit using protocols like SSL/TLS, whereas protocols like SRP require the plaintext of the password to operate.
Tweaking the PBKDF round count, either on the client or server side, is pointless. Set a fixed round count that makes the hash slow, but not so slow that it will place an undue load on the client or server. (100,000 rounds is probably excessive for a server-side hash. It takes roughly half a second to verify a password with those settings, so just two login requests per second would use 100% of one core on your server!)
On the stellar website FAQ (https://www.stellar.org/faq/#_Why_does_my_client_log_me_out_on_refresh_) it says the following
Your password never gets sent to our server: instead, it’s used in your current browser
window to decrypt your secret key. That way we never have access to your stellars. We chose
not to store this password locally, so that it doesn’t get written to your local disk (we
may add the ability to cache the password locally, depending on user demand).
How exactly does (or could) this work? The usual workflow would be to send the password to the server, which then hashes it and compares it to the hash stored in a user database. I can't see a way of this working (safely) by only doing it client side...
I'll take a shot, the workflow goes something like this during registration:
I enter my password and submit the form.
This sends a request to the server to get a KEY.
The KEY comes back and is encrypted on the client with the password.
The Encrypted KEY is sent to the server.
The Encrypted KEY is stored in the database.
During Login:
I enter my credentials and submit the form.
This sends a requested to the server to get my KEY.
The KEY comes back and is decrypted on the client with the password.
Presumably at this point some sort of 'authorized' message or signal is somehow sent back to the server, or possibly even the unencrypted key?
You ask about this being secure, and well it's not. The are specifically saying this (in their FAQ) regarding why they can't help you retrieve your password, and it does protect your password but it does NOT protect your account.
Anyone that has access to a packet sniffer can get the encrypted key, and depending on the level of encryption possibly break it open. Faking that encryption data going back to the server to verify a login is, I am sure, a joke, given that all of the encryption and decryption code has been passed to the client to be executed during registration or login.
But that's how it's conceivable, at least.
The browser is always in the hands of the enemy!
In this case one wants to authenticate a user via http/s.
In the registration progress the server generates a salt. This salt is send to the user. He then procedes to hash his password with the salt via js and send it to the server.
There the hash get salted again with the same salt and the twice hashed and salted password gets written into a db with the cleartext salt.
If one tries to authenticate he sends his username, gets the salt and hashes the password. This is send to the server who hash it again and if the saved hash and this is the same the user is authenticated.
I was wondering because of the recent heartbleed bug it would be nice to never expose the real password. But I've read that double hashing can increase the risk of collissions.
Is the way I imagined that the safest way or do I get soimething wrong?
"In the registration progress the server generates a salt. This salt is send to the user. He-" I'm going to have to stop you right there.
In principle, there is nothing wrong with client-side hashing, as long as you understand that it doesn't increase the security of your system. However, hashing/digesting does mean passwords received are always of a very specific form, regardless of the shape of the actual password the user chose, and it means you (as a server owner) don't theoretically know the password of the user that's sending it to you.
It's not secure, because you -and anyone listening in- can take that hashed password and crack it (because you're no different from an attacker in that respect). However, it does add a layer of trust: "I have to go out of my way to find out what your password is".
Taking that into account, salting at the client isn't useful, and if you get the salt from the server, is a false sense of security: if you are sending the salt from the server to the client, anything that can see the user's password client-side can also see the salt client-side. You might as well write the salting value as an <h1> title on the page, there is no security there, and you're just going to waste processor time salting.
Now, you still want to hash properly on the server, with salt, but there is no point in having the client do any salting. Simply give them a client-side digester/hasher (like a SHA256 library) and leave it at that. Then on the server, you receive the password, validate it against what you know about what hashed passwords should look like (right length? no characters outside the hashing space? etc) and then you hash that input with your own salt and store that/use that to validate against your user database.
I was wondering because of the recent heart bleed bug it would be nice to never expose the real password.
I can see where you're coming from, but you haven't thought this all the way through. If you hash the password client side and send the hash to the server, then this hash is essentially the user's password. If an attacker were to gain possession of this hash that the client sent to the server, whether it be through heartbleeding, MITM attacks or otherwise, all the attacker has to do is send this hashed password to your server (without hashing it again client side obviously) in order to log in. Hashing it client side gains you nothing.
But I've read that double hashing can increase the risk of collisions.
Theoretically yes. If the password is longer than the resulting hash, the entropy of the input is guaranteed to be reduced. Even with input shorter than the resulting hash, chances are that the entropy is reduced somewhat. Hashing this reduced entropy data again reduces entropy further (theoretically). In practice this will hardly matter at all.