On the current project I'm working on, we have the following problem.
Our software is a Location Based Services platform and applications can connect and use our services through our exposed webservices using SOAP. Until now our platform was only used by internal applications, but now we would like to open it for third party applications. For that we need an authentication mechanism.
Because of our customers' infrastructure and load balancing solution, we cannot use HTTPS. The original idea was that applications can just use HTTPS and send the password we authenticate.
A solution would be the next:
The application has the password. The application generates a random string (salt) and creates a hash. Then the application creates an HTTP request sending the hash, the salt and a timestamp. This three is enough for us to authenticate, as we can generate the same hash and compare.
My problem is that for this we need to store the password in our database in clear text, because we need to do the same process using the given salt so we can compare the result and authenticate the application. Storing passwords in clear text is unacceptable.
Do you know about any authentication/access control mechanism that would fit this situation? Generally, do you know about any good books/sources about application authentication/access control mechanisms?
Any help is highly appreciated. Thanks in advance!
The application (client) can hash the password two times. Note that the server should generate the other random salt, not the client! Otherwise the attacker can log with this hash also. You can also make it safer by storing password specific salt in the database.
The protocol:
0) servers retrieves salt for that particular password from database, generates salt2, and sends both to the client
1) client sends hash(hash(password, salt), salt2, timestamp) and timestamp.
2) server retrieves hash(password, salt) from the database and compares.
Note that if you are on the network where attackers can not only sniff, but also modify the traffic, as Paulo pointed out, you should sign EVERY message: hash(hash(password, salt), salt2, timestamp, message) and check it at server. (E.g. for the case when the attacker could modify the message to contain delete command...)
Note that there is still a problem when user needs to SET/CHANGE the password safely. You cannot do it safely with just hash function over unsafe network, you need some kind of cipher/decipher.
Also note that the slower the hash function is, the safer (because of the dictionary attack). If you don't have access to special slow hash function, you may also call normal fast hash function 100000 times.
Instead of inventing your own solution, you should use an established one. SOAP has support for cryptographic authentication such as WS-Security - see Craig Forster's comment on this answer for suggestions.
The best choice in other cases is usually oauth; it provides both authorization and authentication, and deals with a lot of cryptographic issues that you're not likely to spot when building your own.
Using an authentication solution which does not contain an integrity check of the whole message (or stream) is insecure.
While the hashing solution originally proposed by Thomas T. (hash(hash(password, salt), salt2, timestamp), where hash(password, salt) is stored in the database, and salt2 is newly generated) makes sure than an attacker can't get the password (or any data which will be useful for logging in after the timestamp expires), it alone does not prevent an active attacker to hijack the session after the authentication, and send any SOAP requests wanted (and intercept the responses).
What would be needed here is some way to make sure that no data is changed. This is known as a message authentication code (MAC). The usual definition of a MAC includes some (shared secret) key and the message as input, and an authentication token as output.
The usual way to use this would be to do some authenticated key exchange at the beginning of the communication (using either a shared secret or some known public key), and then use a part of the now shared secret as the MAC key, which is then used to authenticate following messages.
(Doing this then essentially is a reinvention of SSL/TLS (or parts thereof), potentially doing the same mistakes again.)
If you have only one message to send, you can instead use the MAC as a kind of symmetric signature, using the password hash (salted and generated with a slow hash function) as a MAC key.
Another way to view this would be to take the message to authenticate as an input to the outer hash in Thomas T's authentication scheme. (Make sure to authenticate everything that is worth authenticating.)
Related
I need to make a log-in system and having basically no previous knowledge of how it's done (with security in mind) I studied it on the internet. The way I would do it now is something like this:
Server has login information in a database table - username and a password hash per user (encrypted with SHA224 for example).
When client wants to authenticate, password is encrypted with SHA224 (client-side) and sent with username to the server to verify a match in the database.
If the user ticked "Remember me" option, an authentication key is generated on the server, inserted into a database along with the IP of the client.
The authentication key is sent to the client and stored in cookies.
Now, when the client returns, authentication key from cookies is sent to the server, the server finds it in the database and checks if the IPs match as well. If it does, the user is authenticated and a new authentication key is generated and sent to the user (and stored in cookies) for next visit.
My questions are:
How does encrypting password make this any safer? The hash still can be captured on the way from client to server and misused just as well as if it was plaintext. I know that this is an elementary question but I somehow couldn't find an answer to this one.
Is this security system secure enough? (or better yet - Did I get it right?)
Why does hashing a password make the system more secure
Hashing is not equal to encryption. Encrypted data can be decrypted back into plain text. Hashed data cannot be decrypted.
By hashing your user's passwords, nobody can see what passwords are used. So if your data gets stolen, the hashes cannot be decrypted by the hacker. The same goes for the system administrator, he/she cannot 'lookup' a password. This can be an all to common scenario in shared hosting environments.
Storing passwords
The easiest way to get your password storage scheme secure is by using a standard library.
Because security tends to be a lot more complicated and with more invisible screw up possibilities than most programmers could tackle alone, using a standard library is almost always easiest and most secure (if not the only) available option.
The good thing is that you do not need to worry about the details, those details have been programmed by people with experience and reviewed by many folks on the internet.
For more information on password storage schemes, read Jeff`s blog post: You're Probably Storing Passwords Incorrectly
Whatever you do if you go for the 'I'll do it myself, thank you' approach, do not use MD5 anymore. It is a nice hashing algorithm, but broken for security purposes.
Currently, using crypt, with CRYPT_BLOWFISH is the best practice.
From my answer to: Help me make my password storage safe
As for the infamous remember me option.
Create a random token and give it to the user in the form of a cookie.
If the user presents a cookie with this token, you give them access. Key is to only accept each token once. So after it is used, replace it with a new random token.
This token is, in essence, just another password. So in order to keep it safe, you do not store the token, but a hash of it. (just as you did with the password)
Your suggestion of binding the cookie to an IP-address will unfortunately not work. Many people have dynamic IP-addresses, some even change from request to request during a single session. (this is for example caused by load-balancing proxies).
Sending passwords to the server
The only method currently usable for sending a password from a web browser to server is by using a SSL-secured connection. Anything else will not be safe, as you cannot guarantee the integrity of the solution on the client side.
Some points I want to add:
the hashing of the password is not done on the client. You cannot do it reliably. The necessary technique for computing the hash (JavaScript in your case) might not be available and you cannot trust the result. If somebody can retrieve the hashes of the passwords in your database he could just login without knowing the actual passwords.
make sure to use SSL or another secure transport for transmitting the given passwords from the client to the server. SSL is a good idea for everything after all.
you should not use a single hash algorithm for storing the passwords in the database. Have a look at HMAC. That is far better. Additionally read about salts in cryptography.
Never ever invent your own crypto
mechanisms. Use someone else's.
Crypto is beyond tricky, and unless
you're Bruce Schneier, you have an
extremely slim chance of improving
it, while having a huge chance of
screwing it royaly.
Do not encrypt passwords, hash them.
If you're using hashes, salt them.
If you don't have
to use straight hashes, use HMAC,
they're much more resistant to
precalculated attacks.
If you're
sending stuff across an unsecure
link, add a NONCE to the transmission
to prevent replay attacks. This goes
for both client->server and
server->client.
If you're using salts and nonces, make sure they have high entropy. 'secret' is not a good one. Make it random, make it long, make it use large character sets. The extra computation cost is minimal, but the security you gain from it is enormous. If you're not sure how, use a random password generator, and then use ent to measure entropy.
Do NOT use a
timestamp as a nonce, unless you have
a very specific need and really know
what you're doing.
Use session
protection. SSL isn't perfect but
it's helluva better than nothing.
If you're using SSL, make sure to disable weak protocols. SSL session starts with 'offerings' of lists of ciphers both sides can do. If you let clients use a weak one, an attacker will definitely use that.
Many users – myself included – would like the security of having everything they do on a web service encrypted. That is, they don't won't any one at the web service to be able to look at their: posts, info, tasks, etc...
This is also major complaint in this discussion of an otherwise cool service: http://news.ycombinator.com/item?id=1549115
Since this data needs to be recoverable, some sort of two-way encryption is required. But unless you're prompting the user for the encryption key on every request, this key will need to be stored on the server, and the point of encrypting the data is basically lost.
What is a way to securely encrypt user data without degrading the user experience (asking for some key on every request)?
-- UPDATE --
From #Borealid's answer, I've focused on two possibilities: challenge-response protocols, where no data (password included) is sent in the "clear", and non-challenge-response protocols, where data (password included) is sent in the "clear" (although over HTTPS).
Challenge-response protocols (specifically SRP: http://srp.stanford.edu/)
It seems that its implementation would need to rely on either a fully AJAX site or using web storage. This is so the browser can persist the challenge-response data during encryption and also the encryption key between different "pages". (I'm assuming after authentication is completed I would send them back the encrypted encryption key, which they would decrypt client-side to obtain the real encryption key.)
The problem is that I'm either:
fully AJAX, which I don't like because I love urls and don't won't a user to live exclusively on a single url, or
I have to store data encryption keys in web storage, which based on http://dev.w3.org/html5/webstorage/ will persist even after the browser is closed and could be a security vulnerability
In addition, as SRP takes more than one request ( http://srp.stanford.edu/design.html ), there needs to be some persistence on the server-side. This is just another difficulty.
Traditionally
If I'm ok transmitting passwords and data in the clear (although over HTTPS), then the client-side issues above are not present.
On registration, I'll generate a random unique encryption key for the user, and encrypt it using their password and a random salt.
In the database, I'll store the user's password hash and salt (through bcrypt), encrypted encryption key, encryption key salt, and encryption iv.
After an authentication, I'll also need to use their password to decrypt the encryption key so that they may view and enter new data. I store this encryption key only temporarily and delete it when they explicitly "log out".
The problems with this approach is that (like #Borealid points out) evil sysadmins can still look at your data when you are logged in.
I'm also not sure how to store the encryption keys when users are logged in. If they are in the same data store, a stolen database would reveal all data of those who were logged in at the time of theft.
Is there a better in-memory data store for storing these encryption keys (and challenge data during an SRP authentication)? Is this something Redis would be good for?
If the data need to be recoverable in the event of user error, you can't use something like a cookie (which could get deleted). And as you point out, server-side keys don't actually secure the user against malicious sysadmins; they only help with things like databases stolen offline.
However, if you're running a normal web service, you've already gotten pretty lucky - the user, in order to be unique and non-ephemeral, must be logged in. This means they go through some authentication step which proves their identity. In order to prove their identity, most web sites use a passed credential (a password).
So long as you don't use a challenge-response authentication protocol, which most web sites don't, you can use an encryption key derived from a combination of a server-side secret and the user's password. Store the encryption key only while the user is authenticated.
If you do this, the users are still vulnerable to sysadmins peeking while they're using the service (or stealing their passwords). You might want to go a step further. To go one up, don't send the password to the server at all. Instead, use a challenge-response protocol for authentication to your website, and encrypt the data with a derivative of the user's password via JavaScript before uploading anything.
This is foolproof security: if you try to steal the user's password, the user can see what you're doing because the code for the theft is right there in the page you sent them. Your web service never touches their data unencrypted. This is also no hindrance to the normal user experience. The user just enters their password to log in, as per normal.
This method is what is used by Lacie's storage cloud service. It's very well done.
Note: when I say "use foo to encrypt", I really mean "use foo to encrypt a secure symmetric key which is then used with a random salt to encrypt". Know your cryptography. I'm only talking about the secret, not the methodology.
None of those other solutions are going to maintain the feature set requested -- which specifically wants to preserve the user experience. If you look at the site referenced in the link, they email you a nightly past journal entry. You're not going to get that with JavaScript trickery per above because you don't have the browser to depend on. So basically this is all leading you down a path to a degraded user experience.
What you would want, or more precisely the best solution you're going to find in this space, is not so much what wuala does per above, but rather something like hush.com. The handling of user data needs to be done on the client side at all times -- this is generally accomplished via full client-side Java (like the Facebook photo uploader, etc), but HTML/JavaScript might get you there these days. JavaScript encryption is pretty poor, so you may be better off ignoring it.
OK, so now you've got client-side Java running a Journal entry encryption service. The next feature was to email past journal entries to users every night. Well, you're not going to get that in an unencrypted email obviously. This is where you're going to need to change the user experience one way or the other. The simplest solution is not to email the entry and instead to provide for instance a journal entry browser in the Java app that reminds them of some old entry once they get to the website based on a link in the daily email. A much more complex solution would be to use JavaScript encryption to decrypt the entry as an attachment inline in the email. This isn't rocket science but there is a fairly huge amount of trickery involved. This is the general path used by several web email encryption services such as IronPort. You can get a demo email by going to http://www.ironport.com/securedemo/.
As much as I'd love to see a properly encrypted version of all this, my final comment would be that journal entries are not state secrets. Given a solid privacy policy and good site security semantics, I'm sure 99% of your users will feel just fine about things. Doing all this right with true security will take an enormous amount of effort per above and at least some design/UE changes.
You should look into the MIT project CryptDB which supports querying an encrypted database using a subset of SQL. (see the forbes article, mefi thread, or Homomorphic encryption on wikipedia)
There is the Tahoe-LAFS project for cloud storage too, which conceivably could be leveraged into a fully anonymous social networking application, one day in the distant future.
If you want to perform computations on a server without even the server being able to see the data, you may be interested in knowing about fully homomorphic encryption. A fully homomorphic encryption scheme lets you perform arbitrary computations on encrypted data, even if you can't decrypt it. However, this is still a topic of research.
For now, I guess your best bet would be to encrypt all posts and assign meaningless (e.g. sequential) IDs to each one. For a more in-depth discussion of how to encrypt server-side data with today's technology, look up.
I noticed that most sites send the passwords as plain text over HTTPS to the server. Is there any advantage if instead of that I sent the hash of the password to the server? Would it be more secure?
This is an old question, but I felt the need to provide my opinion on this important matter. There is so much misinformation here
The OP never mentioned sending the password in clear over HTTP - only HTTPS, yet many seem to be responding to the question of sending a password over HTTP for some reason. That said:
I believe passwords should never be retained (let alone transmitted) in plain text. That means not kept on disk, or even in memory.
People responding here seem to think HTTPS is a silver bullet, which it is not. It certainly helps greatly however, and should be used in any authenticated session.
There is really no need to know what an original password is. All that is required is a reliable way to generate (and reliably re-generate) an authentication "key" based on the original text chosen by the user. In an ideal world this text should immediately generate a "key" by salting then irreversibly hashing it using an intentionally slow hash-algorithm (like bcrypt, to prevent Brute-force). Said salt should be unique to the user credential being generated.
This "key" will be what your systems use as a password. This way if your systems ever get compromised in the future, these credentials will only ever be useful against your own organisation, and nowhere else where the user has been lazy and used the same password.
So we have a key. Now we need to clean up any trace of the password on the clients device.
Next we need to get that key to your systems. You should never transmit a key or password "in the clear". Not even over HTTPS. HTTPS is not impenetrable. In fact, many organisations can become a trusted MITM - not from an attack perspective, but to perform inspections on the traffic to implement their own security policies. This weakens HTTPS, and it is not the only way it happens (such as redirects to HTTP MITM attacks for example). Never assume it is secure.
To get around this, we encrypt the key with a once off nonce.
This nonce is unique for every submission of a key to your systems - even for the same credential during the same session if you need to send it multiple times. You can reverse said nonce (decrypt), once it arrives in your own systems to recover the authentication key, and authenticate the request.
At this point I would irreversibly hash it one last time before it is permanently stored in your own systems. That way you can share the credential's salt with partner organisations for the purposes of SSO and the like, whilst being able to prove your own organisation cannot impersonate the user. The best part of this approach is you are never sharing anything generated by the user without their authorisation.
Do more research, as there is more to it than even I have divulged, but if you want to provide true security to your users, I think this method is currently the most complete response here.
TL;DR:
Use HTTPS.
Securely hash passwords, irreversibly, with a unique salt per password. Do this on the client - do not transmit their actual password. Transmitting the users original password to your servers is never "OK" or "Fine". Clean up any trace of the original password.
Use a nonce regardless of HTTP/HTTPS. It is much more secure on many levels. (Answer to OP).
Since it's over HTTPS, it's definitely just fine to send the password without hashing (over HTTPS it's not plaintext). Furthermore, if your application is depending on HTTPS to keep it's content secure, then it's useless to hash the password before sending it over HTTPS (i.e. if an attacker can unencrypt the data on the wire, you're screwed anyways)
No, in fact this would be a vulnerability. If the attacker is able to obtain the hash from the database, then he could use it to authenticate without needing to crack it. Under no circumstance should a user or an attacker be able to obtain a hashes password.
The whole point of hashing passwords is to add an extra layer of security. If an attacker is able to obtain the hash and salt from the database using SQL Injection or an insecure backup then he has to find the plain text by brute forcing it. John The Ripper is commonly used to break salted password hashes.
Not using https is a violation of the OWASP Top 10: A9-Insufficient Transport Layer Protection
EDIT:
If in your implementation you calculate a sha256(client_salt+plain_text_password) and then calculate another hash on the server side sha256(server_salt+client_hash) then this is not a serious vulnerability. However, it is still susceptible to eavesdropping and replaying the request. Thus this is still a clear violation of WASP A9. However, this is still utilizing a message digest as a security layer.
The closest thing i have seen to a client-side replacement for https is a diffie-hellman in key exchange in javascript. However, this does prevent active MITM attacks and thus is till technicality a violation of OWASP A9. The Authors of the code agree that this is not a complete replacement for HTTPS, however it is better than nothing and better than a client-side hashing system.
Sending a hash over the wire completely defeats the purpose of the hash, because an attacker can simply send the hash and forget about the password. In a nutshell, a system that athenticates using a hash in clear text is wide open and can be compromise with nothing more than network sniffing.
The password in plaintext show never (not even when using HTTPS) leave the client. It should be irreversibly hashed before leaving the client as there is no need for the server to know the actual password.
Hashing then transmitting solves security issues for lazy users that use the same password in multiple locations (I know I do). However this does not protect your application as a hacker that gained access to the database (or in any other way was able to get his hands on the hash) as the hacker could just transmit the hash and have the server accept it.
To solve this issue you could of course just hash the hash the server receives and call it a day.
My approach to the issue in a socket-based web application I'm creating is that on connection to the client the server generates a salt (random string to be added before hashing) and stores it on the sockets variable, then it transmits this hash to the client. The client takes the users password, hashes it, adds the salt from the server and hashes the whole thing, before transmitting it to the server. Then it's sent to the server which compares this hash to the hash(hash in the DB + salt). As far as I know this is a good approach, but to be fair I haven't read a lot on the topic and if I'm wrong about anything I'd love to be corrected :)
Disclaimer: I'm by no stretch a security expert-- and I'm posting with the hope that others will critique my position as overly cautious or improvable and I will learn from it. With that said, I just want to emphasize that hashing when it leaves your client doesn't mean you get to don't have to hash on the backend before putting it in the database.
Do both
Do both because:
Hashing on the ride over helps cover vulnerabilities of transport, if SSL connection is compromised, they still can't see the raw password. It won't matter in terms of being able to impersonate authorized users, but it will protect your users from having their passwords read in association w/ their email. Most people don't follow best practice and use the same password for many their accounts, so this can be a serious vulnerability to your visitors.
If someone, somehow was able to read passwords from the database (this does happen, think SQL injection), they still won't be able to execute privileged actions impersonating users through my API. This is because of hash asymmetry; even if they know the hash stored in your DB, they won't know the original key used to create it and that's what your auth middleware uses to authenticate. This is also why you should always salt your hash storage.
Granted, they could do a lot of other damage if they had free rein to read what they want from your database.
I just want to emphasize here that if you do decide to hash the key before departure from your clients, that isn't enough-- the backend hashing is, imo, much more important and this is why: If someone is intercepting traffic from your client, then they will see the contents of the password field. Whether this is a hash, or plain text, it doesn't matter-- they can copy it verbatim to impersonate an authorized client. (Unless you follow the steps which #user3299591 outlines, and I recommend you do). Hashing the DB column, on the other hand, is a necessity and not at all difficult to implement.
Use HTTP Digest - it secures the password even over http (but best useage would be http digest over https)
Wikipedia:
HTTP digest access authentication is one of the agreed methods a web server can use to negotiate credentials with a web user (using the HTTP protocol). Digest authentication is intended to supersede unencrypted use of the Basic access authentication, allowing user identity to be established securely without having to send a password in plaintext over the network. Digest authentication is basically an application of MD5 cryptographic hashing with usage of nonce values to prevent cryptanalysis.
Link: http://en.wikipedia.org/wiki/Digest_access_authentication
If you want to see a "real life" use, you could look at phpMyID - a php openid provider that uses http digest authentication http://siege.org/phpmyid.php
.. or you could start from the php auth samples at http://php.net/manual/en/features.http-auth.php
Http digest rfc: http://www.faqs.org/rfcs/rfc2617
From my tests all modern browsers support it...
If you're looking to replace a clear-text password over HTTPS with a hashed password over HTTP then you're asking for trouble. HTTPS generates a random, shared transaction key when opening up a communication channel. That's hard to crack, as you're pretty much limited to brute forcing the shared key used for a (relatively) short-term transaction. Whereas your hash can be just sniffed, taken off-line and looked up in a rainbow table or just brute forced over a long amount of time.
However, a basic client-side password obfuscation (not hash) sent over HTTPS does have some value. If I'm not mistaken this technique is actually used by some banks. The purpose of this technique is not to protect the password from sniffing over the wire. Rather, it's to stop the password from being usable to dumb spying tools and browser plug-ins that just grab every HTTPS GET/POST request that they see. I've seen a log file captured from a malicious website that was 400MB of random GET/POST transactions captured from user sessions. You can imagine that websites that used just HTTPS would show up with clear-text passwords in the log, but websites with very basic obfuscation (ROT13) as well would show up with passwords that are not immediately of use.
Whether there's an advantage, and whether it's more (or less) secure really depends on implementation. There's arguably some advantage, but if you implement it poorly, you could definitely create a solution that is less secure than passing even a plaintext password.
This can be looked at from the perspective of two types of attacks-- one with access to the network traffic, and another with access to the database.
If your attacker can intercept the plaintext version of the network traffic, then seeing a hash of the password is more secure than seeing the password in plaintext. Although the attacker could still log in to your server using that hash, it would require a brute-force crack (sometimes pre-computed) of that hash to determine the password that might be useful on other systems. People should use different passwords on different systems, but often don't.
If an attacker gained access to the database, perhaps through a copy of a backup, then you'd want to ensure that one couldn't log in with only that knowledge. If, for example, you stored a hash salted with the login name as hash(login_name+password), and you passed that same hash from the client for direct comparison, then the attacker could pick a user at random, send the hash read from the database and log in as that user without knowing the password, increasing the scope of the breach. In that case, sending the password in plaintext would have been more secure because the attacker would need to know the plaintext in order to log in, even having a copy of the database. This is where implementation is key. Whether you send a plaintext password or a client-side hash of that password, you should hash that value at the server-side and compare that hash with the hash stored in the user record.
Concepts to keep in mind:
You "salt" a hash by mixing in some scope-unique value to your hash, typically row-unique. Its purpose is to guarantee uniqueness of hashes from each other even if the plaintext values they represent are the same, so two users with the same password would still have different hashes. It's unnecessary to treat a salt as a secret.
When authenticating, always hash on the server-side whatever value you pass from the client as a password (even if it's already hashed) and compare it with a pre-hashed value stored on the database. This may necessitate storing a double-hashed version of the original password.
When you make a hash, consider adding a server/cluster-unique salt to the hash as well as a row-unique salt to safeguard against matching any pre-computed hashes in lookup tables.
If you're connected to an https server the data stream between the server and browser should be encrypted. The data is only plain text before being sent and after being recieved. Wikipedia article
If you want to achieve the same reliability as when transferring over https, then yes - one option - the implementation of an asymmetrically encrypted channel at the ajax level.
If we are not talking about registration (for example, the first transmission of the password is always protected), then there are options.
For example,
The server generates a random string and generates a salt sends it to the user.
The user calculates a hash from his password and using this hash as
a key encrypts this random string with a blowfish, for example (there
is an implementation in JS for sure) and sends it back to you.
You, on your own, using the hash stored on the server, also encrypt this
random string with a blowfish.
Compare.
An attacker would have to attack the bluefish key using a random source and ciphertext. The task is not easy.
Isn't SSL/TLS replacing the nonce? I don't see added value of this since SSL/TLS also protects against Replay Attacks.
Ref.
https://en.wikipedia.org/wiki/Cryptographic_nonce
It would actually be less secure to hash the password and send it over a non-encrypted channel. You will expose your hashing algorithm on the client. Hackers could just sniff the hash of the password and then use it to hack in later.
By using HTTPS, you prevent a hacker from obtaining the password from a single source, since HTTPS uses two channels, both encrypted.
If you were to hash a user's password prior to sending it across the line and leaving it in plain-text in memory, would this improve the security of the application?
I would assume this mitigates a small fraction of vulnerabilities by protecting the data stored in the clients memory. But really if we're worried about someone reading the client's memory there are probably bigger problems that we can't address.
There's something that doesn't feel right about hashing on the client's end.
Is password hashing on the client end a common practice? Are there any other advantages or disadvantages to doing it?
EDIT:
Given the communication channel is secure (SSL). Under what conditions would it be acceptable and worthwhile to use such an approach. I'm asking this because it was suggested by a "security professional" that I use such a scheme during some application functions.
No.
When the client sends something, whether it is P or H(P) or H(H(P)) anyone who intercepts this can simply resend the exact same thing, thus making any function like this equivalent to using the password directly.
That's why you should use a nonce; The server can give out some random garbage k and the client will calculate H(P,k) and send it to the server. HMAC is a popular implementation of this method.
Provided the server never accepts the same nonce twice, this is secure against a replay attack.
Sending a hashed password won't improve security on your site, as others have pointed out (since you accept a hashed password, all the bad guy needs to know is the hashed version). It's also not really secure, since the bad guy can presumably load your login page and examine the Javascript or Java deployed.
What it does do is prevents somebody watching the packets from being able to pull out a password, and that is moderately useful. Many people use the same password on multiple sites (I do it for all but the higher security sites), and therefore if you can get one password from them you can log into other accounts on other sites.
It also prevents the real password from being stored, even temporarily, on your site, and that may provide a little extra security if your site is compromised.
So, while I'd consider user-side hashing to be potentially a good things, it isn't worth going to much extra trouble.
And, as others have told you, don't roll your own security. There's far too many things that can go wrong. You won't notice them nearly as fast as a practiced bad guy will.
The hash is identical to the password from a security POV in the scenario you describe: if I intercept the hash, I don't need to know the password, I can just send the server the hash I intercepted.
Authentication protocols go to some length to avoid this problem; security is hard, and you are best off selecting and implementing a well-understood protocol rather than rolling your own.
If your traffic is going over SSL, you're safe from interception and hashing gives you little extra benefit.
Yes, you should.
IEEE had a data breach in which 100K emails and passwords were exposed from a weblog.
http://ieeelog.com/
Obviously, IEEE should not have exposed their weblog! But if they had hashed the passwords at the client side, this wouldn't have been nearly as bad.
As the first answer states, you should use a nonce. If you use a long enough nonce (e.g. 128 bits), you don't really need to worry about reuse, as the server will never ask for the same nonce twice (assuming correctly seeded CRNG, etc.).
No, hashing at the client does not protect the password 'completely'. When one opts to hash the password at the client, then the digest submitted to the server, essentially becomes the password. This is not a problem in itself if SSL is deployed.
However, this scheme ends up creating more problems than it solves. If the server were to compare the hash submitted by the client with a stored hash in the database without performing any further cryptographic operations (especially hashing the input data), then the password is stored in clear text for all practical purposes. Any person with access to the stored hash can re-submit it to the server and gain access to accounts.
In simple terms, if the submitted hash (which is the same as the submitted hash) were to leak via any other vulnerability within the application (via SQL injection, for instance) then the application has a vulnerability where in it protects the passwords inadequately.
If the underlying vulnerability must be fixed, then it is necessary to treat the submitted hash as a password in clear text, which should then be hashed (with a salt preferably) before comparison with a stored hash.
I think it makes sense in one circumstance; you don't want to even know the client's plaintext password. If you hash at the client side, then salt and iteratively hash that hash the same way you would a plaintext pw. Other than that, its kinda silly.
Just make sure that you are sending your password through a secure channel (SSL). If the client can have an application private memory read, then most likely they have bigger problems, like for example a keylogger.
You'd be much better off if you used the Secure Remote Password protocol (SRP). It was designed for this.
I can give you different kind of approach
If you have not SSL you can hash password on client side and again it hashed on server side using another hashing method and store them on database
and when user login with password do the same process and match double hashed password with stored hashes
Yes it makes sense to hash the password on the client side even if you use SSL but still you must also hash it again on the server side.
This makes sense especially in case of a mobile app. If you hash on the client side even with a "constant salt"/domain string it will be much better than sending a password in plaintext even if you use SSL. If you send plaintext passwords to the server then in case someone hacks your server he will receive password in plaintext. So adding additional pre hashing on client side protects the users and their password which they probably use also in other places.
You will probably find many posts saying that client side hashing is not needed but they usually are related to a web apps and do not consider mobile app case. In case of a web app if someone hacks the server he can replace the website and remove the client side hashing anyway so in such case there is not that big advantage. But for mobile apps an attacker cannot replace code of the mobile app so hashing on the client side has a lot of sense in such case.
You can check this link for a possible solution with hashing on both client and server side: https://medium.com/#harwoeck/password-and-credential-management-in-2018-56f43669d588
So yes, hash on both client and server side.
Hashing on the client side opens up another huge hole: you may expose the hashing algorithm. You don't say whether this is web-based (client=JavaScript) or thick-client, but you're giving them more information. Given the channel is secure, you don't have to worry about the clear text password being sniffed.
Besides, if your hashing algorithm requires a salt, you would be exposing your salt, which means if they ever got access to the database, they would be able to decrypt every password.
Situation 1 - Connecting the server to the database:
Its always said that passwords should not be stored in plain text, however to connect to the mysql database requires the password, in plain text it seems... I'm guessing the best solution to this is to store it in an encrypted form, decrypt it in my app as needed and then erase it from memory (SecureZeroMemory in windows I guess so the compiler cant optimise it out).
Situation 2 - Users logging into the server from a remote computer:
As for users passwords my plan is to never actually store the original password at all.
Instead I will store a randomly generated "salt", for each user, prefix there password with it then hash it, which seems to be a relatively common way. However I don't have an SSL connection available at this point, so I'm guessing the plain text passwords could be intercepted, what's a good solution to this?
What are good algorithms (links to C/C++ implementations would be handy as well if you have them) for doing this, a look on the net comes up with 100's of them?
EDIT:
If I got SSL, would the following be secure (assuming a strong hash algorithm is used), or should a different method be used?
Client requests salt for a user name
Client prefixes password with salt, then hashes it before sending the hash to the server
Server compares hash recieved to the one on the server for that user name
Connecting the server to the database
Just storing the database password in the server - encrypted or not - is a bad idea. It is obvious storing it in plain text, of course. And if you just store it encrypted, the server still needs the key to decode it. It is usually not very hard to find the key in the server code. The best solution is to let the user starting the server enter the password and store it nowhere. Alternatively - and probably even better - you can store all sensitive information - for example database users, passwords, and so on - encrypted and let the user starting the server enter a master key to decrypt this information.
Connecting a user to the server
This is really a hard problem and easy to mess up. A quote from this great article article on the topic I absolutely recommend reading.
No, really. Use someone else’s password system. Don’t build your own.
A good solution might be using the Secure Remote Password Protocol.
You are correct that if you're not using SSL then the passwords can be intercepted.
It is common practice to never decrypt a user's password, so keep it stored hashed with a salt and when the user types in their password you will add the salt and hash it, comparing it with the stored, hashed password. This will allow you to never have the decrypted version of the password every.
You really should look into securing the connection so that the password is secure when the user types it in.
Update to answer edited question:
If you have the communication secured using SSL you can still use any number of extra measures of security you like including hashing the password. As added security it is a good idea to remember that the password you store should be stored hashed with a salt. That salt should be kept safe and never be accessible anywhere except by your application. This way when the user submits the password you just add the salt and hash and you compare that version with the stored version.
Situation 1 - Connecting the server to the database
There isn't an easy answer here. In order to connect, the server needs the password (or symmetric key, or private key or whatever). It must get it either from the disk or some external means (like an administrator typing it at startup). Adding some indirection, such as encrypting all the sensitive stuff under a master password, can add some convenience but otherwise doesn't change the situation.
Typically, it is fine to put the password or key in a file on a server. If you do this, make sure to set the permissions on the file so that only the users that need it have access to it. This is an excellent reason to have different processes on your system run as different users, and to set up separate roles/accounts and passwords for each.
Situation 2 - Users logging into the server from a remote computer
You are headed in the right direction here, I think. What it sounds like you're asking for is a secure authentication protocol. You want one that provides mutual authentication and prevents a man-in-the-middle attack by failing if such an attack is attempted. There are many to choose from of course.
It is also worth mulling whether your authentication should operate based on "something you know" (passwords) or "something you have" (public/private keys). Assuming based on your question that what we're looking for is passwords, two that I like are SRP and Kerberos.
SRP was mentioned earlier, and that doesn't get nearly the attention it deserves. SRP has the advantage that it doesn't require the server to know the password, or key, or anything that an attacker could use to gain access. If you broke into a correctly configured server using SRP and stole all the data, you'd still need to do something like a dictionary attack on each key individually before you had anything you could use to impersonate a user.
I also like Kerberos because it is supported by tons of software (I know Postgres supports it, I've only found mentions of mysql not supporting any good authentication technology) and has a system of 'tickets' that provides a single sign on capability. Kerberos needs some other technology to help strengthen its initial authentication exchange and SRP would be great for that but I'm not sure they've done that yet. Something about it making the KDC (key server) stateful I think.
Kerberos' weakness is that you have to be more wary of the server storing the keys. While it doesn't store the passwords in plaintext, it does store the keys, which are essentially hashed versions of the passwords. And while the client doesn't exactly send either the password or the key straight over when authenticating (this is a Real auth protocol after all), it does use the hashed password as the key, and so anyone else who knows the algorithm and knows the key could do the same. We say that the server stores a "password equivalent". As a result, all the manuals tell administrators to put the kerberos services on their own separate, locked-down boxes to minimize the chance of compromising their contents.
The nice thing is, once you settle on a strong authentication exchange, other good things typically fall out of it for free. You end up with both parties sharing a mutual 'secret' that can be used once for the duration of the session, never sent over the wire, and can't be known by a third party. Want encryption? There's the key, all ready to go. This is exactly how SRP-secured SSL is defined in RFC 5054.
Not sure if this is what you are asking for.
But a simple PHP example using the built in sha1 function:
// Check the hashed password from the database
if (sha1($salt.$password) == $providedPassword)
{
// User is authenticated
return TRUE;
}
else
{
// User is not authenticated
return FALSE;
}
One thing you could do is also hash the password with javascript before it is sent over the wire. The question is how is the salt string shared between client and server? One possibility is to use a session variable. And then use the session variable to unhash the password afterwards on the server. This would mean that the man in the middle would need to know one other piece of info to make sense of the password. Not as secure as SSL, but perhaps an extra layer of defense against casual network sniffers.
I could also imagine a hashing scheme linked to some sort of captcha system used to salt the password on the local client before sending over the wire. The client would be providing the text for the salt string by completing the captcha. You could look it up on your end.
The main concern is the man in the middle not understanding the plain text password.
SSL should be used, but the above techniques might be useful where SSL is not possible.
Newer MySQL uses hashed password over the wire, so you don't have to worry about man-in-the-middle.
If you worry about the password stored in your configuration file, you can encrypt the configuration file with a password. However, the problem is that you have to enter a password to start your application.
I wrote a similar application over 15 years ago. Back then, PGP was my choice. I am not even sure it's still around.