Potential security issues with storing bcrypt hash in local storage? - security

I'm building a website that uses a password to encrypt/decrypt text. I'm storing the bcrypt hash of the password in database and check whether the password is correct before decrypting.
I want the website to also work offline and the only way I can think of doing this is localStorage.
What are the security considerations that I should take before storing password hashes in local storage?

An interesting question! Without knowing more about your threat model (what's the worst thing an attacker could do with the cracked password that they couldn't do because they now have access to the client endpoint?), I can answer generally.
While password hashes are designed to be resistant to offline / local attack, that's a last resort - they're really intended to be entirely out of reach of the attacker, so they can't be guessed repeatedly at the attacker's leisure with arbitrary local compute resources and with no throttling. (As the attacker, having a password hash to attack is exactly what I need to get started!)
But since you're specifically protecting what will effectively be a local decryption key, the hash might indeed need to be stored locally. If so, I would recommend making the bcrypt 'cost' (work factor) as high as the user can tolerate. (Since the work to validate the hash is distributed per client, you can afford to make that cost significantly higher than you might be able to absorb on the server, to mitigate thundering herds).
So if the user can tolerate having to wait for a couple of seconds, a bcrypt cost of 16 might be a reasonable client-side value (but you'll need to test this for your own use cases, and the value will also change over time). Make the number as high as your users can take.

Related

Clientside password hashing

A friend of mine and me are having a discussion about whether we should pre-hash the passwords of the users of our webapp before sending it to our servers.
I know that there are multiple questions that already handle this topic but they're all about transferring it securely to the server. Our idea is not about the transfer security (we use SSL) we want to hash clientside to prevent that the "real" passwords reach our server.
The idea came as Twitter announced their bug that caused passwords to be printed to a logfile in cleartext.
We are currently discussing about whether this concept makes sense or not and how it affects the security of a password (in terms of Bruteforce) if we would hash it with SHA512.
TL;DR:
We want to hash passwords clientside to prevent our servers from getting them in cleartext (we use SSL for transfer).
Does this make any sense?
What algorithm would be best to use for hashing?
The hashed passwords would then serverside be hashed again with bCrypt.
It 100% makes sense: in fact, the concept has been proposed by a number of people, but the difficulty is in implementing correctly. There are a number of pitfalls if you do it wrong, the most direct one is being vulnerable to "pass-the-hash" as #swa66 describes. To prevent that, you need to hash on both sides. The client-side hash should be slow (bcrypt, scrypt, argon2, or pbkdf2) whereas the server side hash should be fast (sha256).
EDIT: A number of people have down-voted this without understanding how this works, so I now include the basic details here (previously I only linked to how this works). The idea is to apply a slow hash such as bcrypt on the client side, and then a fast hash such as SHA256 on the server side. The fast hash is required to prevent pass-the-hash attacks. In the event of the database leak, an attacker either hash to invert the fast hash (impossible -- violates the one-way property of a cryptographic hash function), or brute force the preimage to the fast hash (impossible -- the size is the length of the output from the slow hash, for example 184-bits for bcrypt), or brute force the combination of the slow hash and the fast hash -- which puts the attacker back at the same position as if the entire computation had happened server side. So we have not reduced the security of password attacks in the event of a database leak by shifting the heavy computation to the client side.
I've surveyed a number of proposals like this in Method to protect passwords in databases for web applications. Additionally, I analyse the pros and cons and identify weaknesses that have not been identified before (account enumeration), and propose a unique way of doing this securely. The research is built off a number of sources, including:
Secure authentication: partial client-side key stretching… please review/criticize my idea
How to securely hash passwords? -- see section on Client Side Hashing
Client side password hashing
Discussion from various authors on Hacker News -- see comments from oleganza, mschuster91, crusso, etc...
You cite the Twitter example, and GitHub did similarly. When I wrote the paper above, the most prominent example for preventing a server from seeing the clear text passwords was Heartbleed, which I comment on in the paper (bottom of Section 1.3).
There has been subsequent follow up research by others identifying similar ideas -- Example: Client-Plus-Server Password Hashing as a Potential Way to Improve Security Against Brute Force Attacks without Overloading the Server. No one person deserves all the credit, but the main takeaway is yes it is a good idea if you do it securely, but you really need to understand the risks (it is easy to do insecurely if you have not read the research).
While #swa66 outlined how to manage passwords securely, let me note that there is a valid scenario where you can consider client-side password hashing, so don't just blindly follow "best practice", try and understand it first.
Let's say I have a standard web application that stores data from users. In my threat model, I don't even want my own users to have to trust me, or in other words, I want my users' data to be secure even in case of a full compromise of my servers. Therefore, I let them choose a password, and encrypt their data on the client, before sending it to the application. They can retrieve their encrypted data with their user id. Well, that doesn't sound very secure, I can just download anybody's encrypted data and run offline attacks against it. So let's have them access their encrypted data with their password (I don't want them to have to remember two different passwords). But that's not good, because I have their password then to decrypt their data. So one simple solution is to encrypt their data with their password, and send it to the server along with their hashed password, which as it's correctly noted in the answer is the new password as far as the server is concerned (so the server should store it hashed once again and so on). However, the server has no way to decrypt client data, because it never has the original password, yet only the valid person can download even their encrypted stuff, and they only have to remember one password. (Note that this is a very much simplified model, in reality, much more is needed, like for example a proper key derivation function, not just plain hashes, but that's another, much longer story.)
Don't get me wrong, I'm not saying you should normally be hashing passwords on the client - no, the other answer is the correct one in that regard. I just wanted to show that there is at least one use-case where client-side password hashing is a valid option. See well-known password managers, some work similarly.
NO!
Rule one in cryptography: do not invent it yourself, you'll make horrible mistakes.
It's not against you personally, by far not: even top notch experts make mistakes when designing with great care new systems. That's why they peer-review each-other's work multiple times before anything become a standard. Many proposals for such standards by such experts get redrawn due to problems detected during such a peer-review. So why can't the rest of us mere mortals design: there's nobody good enough to do the peer-review as the experts will not touch it.
Hashing the password client side
Hashing client side is really bad as the hash becomes the password, and now you store it on the server in the clear.
How to do passwords
Only store hashed passwords (implied: send the password to the server, just do not store it)
use a salt and store it with the password (unencrypted). The salt is essentially a random string that you concatenate to the pasword before you hash it (to store it , and to verify it)
Use a SLOW hash. Using a fast hash is a common and fatal mistake, even when using salts. Most hash functions people know like SHA-256, SHA-3 etc. are fast hashes and completely unsuitable for hashing short, predictable items like passwords as they can be reversed in a surprising short time.
How slow: as slow as you can afford. Examples of slow hashes:
bcrypt, PBKDF-2 (which is essentially a high number of rounds of a
fast hash to make it slow)
There are -depending on your programming environment- pre-made routines, use them!
Ref:
https://crypto.stackexchange.com/questions/24/what-makes-a-hash-function-good-for-password-hashing
https://crypto.stackexchange.com/questions/59797/authorities-on-password-hashing-best-practice

Security implications of generating salts immediately vs. when needed

Say I have a database of users (customers). Some of these customers have logged in through a portal, some of them have not and only exist in the database to facilitate customer management by an administrator. At a later date, customers may decide to begin using the portal, at which point they'll need to be provided a password.
Assuming the randomization method is reasonably secure, are there any security implications related to the timing of the salt generation?
ie.: is it better, worse, or irrelevant to be salting all accounts as early as possible vs. salting only at the time a password is created?
The main idea behind the salts, is to offer protection against rainbow tables, which are databases containing pre-hashed passwords. Having each password salted using a different salt allows you to minimize this risk, since now (in theory) there should be no rainbow table containing your password.
As long as you're using a cryptographically secure pseudo-random number generator (CSPRNG) to generate your salts, there should not be a problem with salting your passwords as early as possible (and it'll be even better if you use the salting mechanism already included in most modern implementations). After all, you only care about always producing a different hash. And salts are not even secret values, if your database got compromised, the attacker will already have the hashed password and the salt (they're usually stored like salt$base64HashedPassword, or they just have a column for the salt), and salts are not like the IVs in cipher block chaining (CBC) where an attacker can take advantage of a predictable IV. Here you only care about always producing a different hash, so as long as you do it, everything should be ok.
Edit: Now I'm curious about something. You're talking about salting the password someday in the future... does that mean that you're storing it as plaintext or in a recoverable way before salting it? Because now that'll be a bad practice. You need to salt it as soon as you get it, since you should not know anything about user's passwords.

does hashing suffice encryption

does using hash functions and algorithims suffice the need to encrypt the data, while communicating with the server
I am applying salt mechanism in my project and I will be concatenating the salt with the entered password, and then hash them all.
do I still need to encrypt the result?
The usual workflow for a website to transmit user passwords looks like this:
The client sends the password plaintext to the server.
The transmission is done with an encrypted connection (HTTPS/SSL), to prevent a ManInTheMiddle attack.
The server calculates a hash of the plaintext password, and this hash is then stored in the database. It is not necessary to encrypt the hash any further.
Make sure you use a random unique salt for each password, and a slow hash function with a cost factor for hashing passwords. Good algorithms are BCrypt, PBKDF2 or SCrypt.
Storing passwords
To store user passwords securely, you need 3 things:
Do not store the plain password, store a hash instead
The hash makes it extremely difficult to recuperate the password even if an attacker manages to capture the entire database
To prevent the use of rainbow tables, you need a salt
The salt is stored in the clear (can be along with the hash) and is random, one for every user and you can easily chose a few one whenever the user changes their password.
You need a SLOW hash, not a fast hash
What are fast hashes: MD5 (consider it broken), SHA-1, SHA-2, ... are unsuitable as the attacker can perform them too fast and use dictionary attacks to try common passwords and find that way up to 95% of you user's passwords in mere hours on modern rigs.
How slow does it need to be ? As slow as you can afford.
And there's a rule 0: Do not invent crypto yourself, you will make serious mistakes before you know it.
Other privacy sensitive info
You're most probably also storing other sensitive information of your visitors in addition to the passwords (email addresses, IP addresses, names, postal address, ...), CC numbers (you better not go there), ...
You need to protect that as well and using hashes isn't the way to do that in most cases. Some of these have requirements and regulations of their own (e.g. Credit Card data is regulated by the issuers who'll force you to be compliant with PCI-DSS).
In essence you need to do a risk analysis and manage that risk by either accepting it ("so be it"), transferring it ("get insurance"), avoid it ("we're not storing that"), or mitigating it ("we're going to improve our way of working").
encryption
Why the media will make you believe there's a "magic" solution in that incomprehensible "encryption" thing, in reality it needs to be done right and in the right conditions to have any meaning at all.
E.g. If you encrypt the entire disk of a server: it will not protect you from an attacker abusing your server scripts and getting to the database (as the database engine and webserver scripts have access to the decrypted disk already)
So, you really need to go back to the risk analysis and chose the measures there instead of getting ahead of yourself and suggesting encryption as a tool that's unlikely to help you for your biggest risks.

Keeping passwords secure during transmission

In my web application, I'm implementing a blacklist of passwords that user's won't be able to select. As mentioned in Jeff's God Login post, this is because some passwords are very commonly used and exist in readily available wordlists used by brute forcing tools.
I had planned to store the blacklisted passwords in a database table (in the clear), with an MD5 hash of it as a Functional Index. So, when the query is sent to the server, it looks like this:
SELECT 1
FROM blacklist AS a
WHERE MD5(a.password) = 'MD5stringOfPasswordSubmitted';
I don't think the "in the clear" storage of these passwords is an issue since the passwords are blacklisted. No user can set it to one of these.. so who cares if passwords in this table are stored in the clear.
But, is the transmission of this query to the database server a problem I should worry about?
If my user is trying to set their password, at the moment the app will MD5 the password, send that to the database to query this blacklist table. If no result is returned, the app will allow them to have it as their password (as long as other validation requirements are also met).
Is this something I should worry about?
Could this be implemented another way so passwords users are trying to set are kept secure still? Is it really necessary to resort to storing a salted hash via Bcrypt (like is in my user table) even just for this blacklist usage? Would using a YAML file in the local directory structure of my app have any of this same risk?
The aim is to prevent users choosing a password that's common, and checking that in a very fast way (hence MD5) as part of the validation process.
I don't see how the transmission of the query could be a problem. If your web application does the MD5 encoding and an attacker intercepts the communication with the database, there is no way he can get back the user's password from it.
MD5 is not safe for storing passwords as attackers may be able to find passwords that result in the same hash value (collisions), but there is no way to convert a hash value back to the clear text from which it originated.
If you're worried about leaking other sensitive data when querying the database, you could consider encrypting the communication channel.
I wouldn't worry about the transmission of passwords since they are hashed using a one-way algorithm (as user18044 pointed out) however expanding more on the weaknesses of MD5 - I wouldn't use that algorithm at all especially if you aren't using a salt. The reason why is because MD5 rainbow tables have been created for a very large set of possible combinations of passwords. In fact it's very likely that the password lists that you are referring to have been generated after searching MD5 tables or using online services that will give you a password by submitting an MD5 hash (if the password has already been cracked previously or is in some table). I would recommend using a salt or using another algorithm like SHA-256. Security is my specialty and I have a rig that is capable of cracking MD5 hashes at hundreds of billions per second however if there is a salt involved it either slows me down or stops me all together (if the salt is not known). That same rig can crack SHA-256 but it takes much longer for it to crack each one because SHA-256 iterates over itself enough times to make each iteration slow enough to make cracking less feasible.
As was already mentioned I would certainly use SSL either way to better protect all data that is transmitted.
But, is the transmission of this query to the database server a problem I should worry about?
This depends on your network topology. e.g.
Is the database server on the same private local network? Then this is low risk.
Is the database server on the same network, but shared with other machines and users. Then this is medium risk (you need to trust all the other machines and users).
Is the database server across the internet? Then this is high risk.
Depending on your accepted risk level, you may want to protect the connection to the database with SSL/TLS.
Even though you are hashing with MD5, MD5 is considered a weak hashing algorithm so if a MITM grabs the password as it is queried on your database, they could run it through a tool such as John the Ripper using a word list and intercept any password set by your users.
You could try and hash the password using another algorithm for this lookup - however this means implementing a "static salt" (called a pepper) on your system to avoid any hash comparisons of intercepted data. It may be much easier to simply connect with SSL/TLS to avoid this completely.
For storage of the password itself (once it has passed your check), definitely use a secure algorithm here such as bcrypt or scrypt.

Securely Storing Password Hashes in Cache

I am making a back-end server as a personal project. Currently, when someone registers, their password is hashed with Bcrypt, and saved in the database. However, querying the database every-time I need to verify that the request came from the authenticated user seems to be too much. As a result, I began to wonder about caching these in the server's memory. I assume that it is unsafe to store an un-hashed password in this memory. What is the most secure way to implement this? I could cache the Bcrypte'd copy of the passwords, and then just verify that the user's password matches the cached Bcrypt copy, but if I can I would like to use bcrypt as little as possible too. I assume that storing a password and its Bcrypt'd version in the cache together, even if not linked to a username, is a bad idea. Is there anything else I can do while keeping security + performance in mind?
Caching clear-text passwords & its hashes is generally not a good idea. Security comes with a cost, here your performance.
If you don't need top-notch security (i.e. slower hashing), you can go for fast hashing solutions based on SHA512.
For database performance, try to tune the database caches for faster retrieval.

Resources