top | item 34497898

Bitwarden design flaw: Server side iterations

474 points| lawgimenez | 3 years ago |palant.info

259 comments

order
[+] jchw|3 years ago|reply
While the practice of not updating PBKDF2 iterations is bad, I think with LastPass the problem was more the aggregate of many things, a sort-of death by a million cuts. Because truthfully, the PBKDF2 iterations count issue was relatively unimportant. Some good conjecture about it:

https://neilmadden.blog/2023/01/09/on-pbkdf2-iterations/

Both Bitwarden and LastPass should improve this situation by making the iteration count automatically increase over time. For LastPass though, there are... A lot of concerns. The breach, how it was handled, persistent issues with the security of their browser extension (many, including an RCE at one point) and of course the fact that not everything in the vault is actually encrypted.

KeePass XC or 1password may prove to be better options from a strict security practices standpoint, but from what I've seen I don't suspect Bitwarden has a pattern of bad security practices overall. It does seem like there are opportunities to make it better, though.

[+] danenania|3 years ago|reply
We took a similar approach to passphrase stretching in EnvKey v1 [1] (EnvKey is a secrets manager, not a password manager, but uses end-to-end encryption in a similar way). We used PBKDF2 with iterations set a bit higher than the generally recommended levels, as well as Dropbox's zxcvbn [2] lib to try to identify and block weak passphrases.

Ultimately, I think it's just not good enough. Even if you're updating iteration counts automatically (which is clearly not a safe assumption, and to be fair not something we did in EnvKey v1 either), and even with safeguards against weak passphrases, using human-generated passphrases as a single line of defense is just fundamentally weak.

That's why in EnvKey v2, we switched to using high entropy device-based keys for our root encryption keys. It's a similar model to SSH, except that on Mac and Windows the keys get stored in the OS keychain rather than in the file system. Also like SSH, a passphrase can optionally be added on top of the device key.

The downside (or upside, depending how you look at it) is that new devices must be specifically granted access. You can't just log in and decrypt on a new device with only your passphrase. But the security is much stronger, and you also avoid all this song and dance around key stretching iterations.

1 - https://github.com/envkey/envkey

2 - https://github.com/dropbox/zxcvbn

[+] hiimkeks|3 years ago|reply
They shouldn't be using PBKDF2 for new installations at all. It's been nearly a decade since the Password Hashing Competition, and you should just use the memory-hard Argon2.

Also, W3C should finally get it into the WebCrypto API, but it seems like whoever is responsible for it just let's that API rot. There are fast wasm implementations, though.

[+] rstuart4133|3 years ago|reply
> Both Bitwarden and LastPass should improve this situation by making the iteration count automatically increase over time.

Bitwarden does let you increase the number of PBKDF2 iterations through a setting, they they also provide this warning:

> Warning: Setting your KDF iterations too high could result in poor performance when logging into (and unlocking) Bitwarden on devices with slower CPUs. We recommend that you increase the value in increments of 50,000 and then test all of your devices.

Translation: upping this could make your old device very slow.

I'm not sure I'd want to be receiving end of a whole pile of users complaining Bitwarden is becoming unusable on their current devices because they silently upped it, so I'm be leery of upping for existing users too.

As for the server side key issue highlighted in the article: they have a point; it could be done better. But it's already pretty good, and if that's the only issue it's the least of my concerns. It's only a concern if a hacker got read access to the server, but read access means they've been compromised. And if they've been compromised those same people might have write access. If someone gets write access to Bitwarden's servers, then all bets are off. They can just modify the javascript to send themselves my unencrypted key.

Then there is the /dev/mem thing. The bottom line is if someone has access to your machines RAM, then you can likely see the entire database unencrypted. Is your Windows desktop "corporate managed"? If so, I'm looking at you, sir. While Linux / Android / iOS are more protective of their users than Microsoft (who seems hell bent on selling their soul to their corporate customers), they aren't whole pile better. They may not sell their soul to high paying corporate customers, but they will still do whatever their governments ask and you will be none the wiser.

The bottom line is all these proprietary solutions suffer from this "we won't let you see but we promise you can trust us" flaw. I refused to use LastPass because it was hopeless in that respect, and later their promises turned out to be hollow. With Bitwarden there is a lot less trust involved because we can inspect the code they promise we are running.

[+] NoPicklez|3 years ago|reply
I still think it's maddening that LastPass's website says that the vault is encrypted, yet in reality that wasn't and may still not be the case, where aspects of the vault as we now know aren't encrypted.

Unless I'm missing something, to me that is one of the biggest failures. It is even laid out in their technical and organizational measures document.

[+] krimpenrik|3 years ago|reply
Just got word that one of my team members runner the python script to extract the seeds out of LastPass. Excited to leave LP and move to bitwarden. Like you said, a lot of small stuff at LP is the issue, unresponsive plugin sometimes, got a update and new UI last week, now the search in the chrome plugin isn't working on my end, really don't understand how you can write such shitty software for something so simpel (the UI part)
[+] tablespoon|3 years ago|reply
> I think with LastPass the problem was more the aggregate of many things, a sort-of death by a million cuts.

That's true.

> Because truthfully, the PBKDF2 iterations count issue was relatively unimportant.

IIRC, some people's LastPass vaults were set to use a very old default of a single PBKDF2 iteration, which I understand is basically nothing, nowadays.

[+] ywain|3 years ago|reply
Oof, my Bitwarden account was created a while ago and was set to only 5,000 iterations. You can see and change the number of iterations here: https://vault.bitwarden.com/#/settings/security/security-key... (or if you don't trust links for something like your password manager: log into your web vault, click on the top-right dropdown menu, then Account settings > Security > Keys).

I've updated it to 600,000 iterations and so far don't see any noticeable impact on performance, both on desktop (using the Firefox extension) and on mobile (iOS).

[+] adament|3 years ago|reply
I am not a cryptographer but to my understanding, the number of PBKDF iterations is really only of concern for weak (low-entropy) passwords. If you know that your password has high entropy (>128 bit), for example because you generated it randomly uniformly from at least 2^128 possible outcomes[1], you are safe even if you used only 1 iteration. PBKDF is all about password strengthening, so if you are making changes for yourself the most effective change is just to use a secure password and stop worrying about key derivation functions.

[1] 28 characters in a single case, 23 characters if both upper and lower case are used, 22 characters if you include numbers, 12 words if you use a word list of 2000 words and sample uniformly

[+] mkasberg|3 years ago|reply
I had bumped mine up once before (to 200K) and I just bumped it up again to 600K. But my wife (registered several years ago, like me) was still at 5K, I just bumped hers up too. Wish Bitwarden would force this for anyone still on an old default - particularly given the LastPass compromise we just saw.
[+] zeven7|3 years ago|reply
As of now, your link is fine (though the comment is probably still editable), and I believe you have the best of intetions but Note: It's not a great idea to click a link to something like Bitwarden, since a phishing domain could be used.
[+] j1elo|3 years ago|reply
Why are you upping it up that much? I guess "too much is not a bad thing" in this case, and Bitwarden itself says: "We recommend a value of 100,000 or more.".

When I see that I read: "With our knowledge of security and encryption, which by the way is much greater than yours, we consider that 100,000 is a perfectly safe number and a good middle point so go ahead and use it".

Am I wrong to think like that? My Master password is a battery-horse-staple thing, but not with 12 words as some other commenter says; that's absurdly long and would be too difficult for me to remember. I usually strive for around 18-20 characters, that's already in the verge of me forgetting it. I use incorrect or derived words of my own (so not really existing in dictionaries).

[+] aidenn0|3 years ago|reply
I updated my master password in 2022, but my account was still set to 5000 iterations. Not increasing it on master key changes seems beyond careless.
[+] sircastor|3 years ago|reply
I upped mine to more than 1M and haven’t seen any degradation of performance.
[+] bjoli|3 years ago|reply
600.000 was a bit too much for my 3 year old low-end android phone. 400k workes OK. when I sorted everything into folders I could bump it up to 600k probably due to time saved rendering.
[+] philliphaydon|3 years ago|reply
Thank you! Mine was also set to 5000, updated to 600k.
[+] fencepost|3 years ago|reply
IMPORTANT NOTE

When you do this reset and sign back into your devices/browser plugins, you will need to go into the Bitwarden Settings on each one and set a few options again - notably timeout (defaults back to Browser Restart, change back to a time you're comfortable with), Biometric Unlock and PIN. All of those are local settings to each Bitwarden client/endpoint, so you need to do them on each device.

[+] realitysballs|3 years ago|reply
Can someone Eli5 iterations in this context?
[+] Kuinox|3 years ago|reply
I've set it up to 2 millions when I created my account. My OnePlus2 freeze for 10 seconds when logging in ^^'.
[+] ajorgensen|3 years ago|reply
oof me too thanks for the nudge to check!
[+] devwastaken|3 years ago|reply
I checked a two year old account and it's at 100k, might have been changed though.
[+] pilif|3 years ago|reply
Tangentially related: why would a password manager provide a configurable iteration count? This is a number whose purpose is fairly hard to understand for many people and yet it’s an important corner stone for password security, especially for those who do not grasp the concept of an iteration count.

This should absolutely be application managed and gradually increased over time.

Also: while I understand that FIPS is the reason why we are stuck with PBKDF2 in the case of the more enterprisy password managers, wouldn’t it still be FIPS compliant to do some scrypt or argon rounds on top as a means of not constantly having to update the PBKDF2 iteration count (assuming that scrypt and argon are more resilient to hardware brute-forcing)?

[+] crumpled|3 years ago|reply
I once leaned heavily upon Google Chrome as my password manager, but then I discovered that you could view the passwords in Chrome for Windows by knowing my Windows login password, instead of my Google password.

This feels off topic a little, but in all the discussion of password managers lately, I seldom hear people talk about the web browser being a good/bad idea. It almost feels like they are slipping through the cracks of the conversation.

For the record, I no longer use that platform for important passwords or secrets, ("driver carries no cash")

[+] avsteele|3 years ago|reply
I still haven't seen a clear explanation of how the # of iterations scales in relation to password length.

If it is true a few extra characters is as good as having sky-high iterations, the guidance should be on 'forcing' users choose long-enough passwords, not in this nitpicking over the 'right' # of iterations.

[+] kadoban|3 years ago|reply
The number of iterations scales linearly with the cost of brute-forcing.

The cost scales exponentially with the length of the password, assuming a random password (stops scaling when you reach the hash size I think).

Both are important because you can't freely increase the password length, they become more annoying to enter and remember.

[+] azeemba|3 years ago|reply
Number of iterations being discussed is how many times the password is hashed. It is a setting the system chooses and is independent of the password length the user chooses.

If you are asking if the length of the password by itself be sufficient to create a secure password, then the answer is mostly no. You need many iterations of the hashing process otherwise brute force attacks become trivial given today's hardware.

[+] fluidcruft|3 years ago|reply
Each doubling of iterations is equivalent to adding one bit of password length.
[+] moughxyz|3 years ago|reply
The way we solve server-side iterations with Standard Notes (which uses Argon2 and not PBKDF2) is to tie the derivation parameters (iterations, bytes, etc) to a hard-coded protocol version number. Accounts which register today for example have a protocol version of 004, which corresponds to specific, immutable derivation parameters.

For a given user, the client then receives from the server not key derivation parameters, but the version of the account. The client then maps that version to the precompiled derivation parameters.

Of course a server can then misreport a user's account version to something lower than it actually is. There are two solutions we implement here:

1. Deprecate older versions as quickly as possible after new protocol version rollouts. Older versions begin to get rejected by clients and clients will not allow sign in to proceed.

2. Allow an optional sign-in flag users can check called "Strict sign in" that forces the client to reject any server provided version that is not specifically the latest version. This means that if a user checks this option and the server reports a version != 004, the sign in will be rejected and the client will not perform any sort of handshake with the server.

More here: https://standardnotes.com/help/security/encryption

[+] ChrisSD|3 years ago|reply
> Even if you configure your account with 1,000,000 iterations, a compromised Bitwarden server can always tell the client to apply merely 5,000 PBKDF2 iterations to the master password before sending it to the server. The client has to rely on the server to tell it the correct value, and as long as low settings like 5,000 iterations are supported this issue will remain.

This seems like a serious flaw that completely undermines setting a custom value, no? If an attacker gets temporary control of a bitwarden server then they can get your password in a more easily crackable form no matter what you set.

[+] doodlesdev|3 years ago|reply
Other than the low amount of default iterations (at least compared to the OWASP recommendation [0]) the article doesn't explain why the server-side hashing is "useless" and what the design flaw actually is. Am I missing something?

[0]: https://cheatsheetseries.owasp.org/cheatsheets/Password_Stor...

[+] artjomb|3 years ago|reply
I disagree with the article that server-side iterations in this case are useless. They are used for access control.

Bitwarden's API likely doesn't permit anybody to access the encrypted blobs of anybody. You have to authenticate at the server to be able to access your blob. Since the iterations might be low for producing the master key and therefore the master password hash, the server must treat the master password hash as just another password and therefore iterate the hash quite often (100,000x).

Assuming no malicious insider or an outside attacker gets their hands on the encrypted blobs this is the most important attack prevention.

[+] FreakLegion|3 years ago|reply
> the 100,000 PBKDF2 iterations on the server side are only applied to the master password hash, not to the encryption key

So only the password hash itself gets the extra iterations. The diagram and the text of the whitepaper seem to be at odds, though. The diagram doesn't show extra iterations for the encryption key, but the whitepaper says:

> PBKDF-SHA256 is used to derive the encryption key from your Master Password. Then this key is salted and hashed for authenticating with the Bitwarden servers. The default iteration count used with PBKDF2 is 100,001 iterations on the client (this client-side iteration count is configurable from your account settings), and then an additional 100,000 iterations when stored on our servers (for a total of 200,001 iterations by default).

[+] amarshall|3 years ago|reply
Quoting directly:

> the 100,000 PBKDF2 iterations on the server side are only applied to the master password hash, not to the encryption key

The attacker doesn’t need to break the master password hash, so it’s irrelevant. This is elaborated in the link directly following the above quote:

> But that protection only works if the attackers are stupid enough to verify their master password guesses via the authentication hash.

[+] curyous|3 years ago|reply
If I understand correctly, the problem is that the hash created on the client side is used to create the encryption key before the server side hashes are applied. Only the master password uses the extra server side hashes.
[+] rcxdude|3 years ago|reply
It's useless in most circumunstances: it depends on what the attacker has access to. If the attacker only has the master password hashes the server uses to gate access to the encrypted database, then they would need to go through the full 200,000 iterations. But if they have the encrypted database then they can run 100,000 iterations and just try to decrypt the database (assuming this check is cheaper than the 100,000 iterations, which it likely is). And it's far more likely the attacker has the encrypted database (which can be pulled off of any machine which has been logged in, as well as the same database which contains the master password hash, if bitwarden's servers were to be breached) than the master password hash alone.
[+] dns_snek|3 years ago|reply
> Testing the guesses against the master password hash would be fairly slow: 200,001 PBKDF2 iterations here. But the attackers wouldn’t waste time doing that of course. Instead, for each guess they would derive an encryption key (100,000 PBKDF2 iterations) and check whether this one can decrypt the data.

I don't understand. As far as I know the key space of PBKDF2-SHA256 is 256 bits and the vaults are encrypted with 256 bit AES. Is the author arguing that Bitwarden is insecure because the attacker could (in a roundabout way) bruteforce 256 bit AES?

edit: I think I understand, the text didn't make it immediately obvious but I believe the author is talking about (configurable) 100k client-side iterations which are then used to obtain the "stretched master key" (from the diagram). This would render the 100k iterations done on the server pointless if an attacker already has a copy of the data, they only protect (slow down) the normal authentication flow.

[+] sacnoradhq|3 years ago|reply
- PBKDF1 (1.0 ?, 1.5 1993)

- PBKDF2 (2.0 2007 RFC 2898, 2.1 2017 RFC 8018) <- This is here, although it was revised in 2017.

- bcrypt (1999)

- scrypt (2009)

- argon2id (2015) <- Have we not yet evolved to address threats here?

What about minimum resource complexity (mem-/CPU-/GPU-/FPGA-/ASIC-hard) guarantees on the client (assumed trusted, as much as one can trust)?

Picking one number out of the sky for today that doesn't evolve with technology doesn't make sense. Plus, it isn't necessarily something a human shouldn't be choosing for every use-case without a risk assessment. There should be a sanity-check lower bound that evolves with best-case performance coupled with a specific threat environment.

Calculator website with:

1. "Which algorithm?" (some choices)

2. "What type of data is it?" (Level 1 - 6 with familiar descriptions)

3. "How long does it need to be protected?" (1...100 years in almost log progression)

4. "How much is the data worth?" (some choices, or 1e2 ... 1e11 USD / other currencies)

5. "What would be the consequences of its disclosure?" (with familiar descriptions)

6. "What model of device will slower users have?" (some choices of new to old laptops and touch devices)

7. "Funding amount of highest reasonable threat actor?" (some choices, or 1e5 ... 1e12 USD / other currencies)

8.-11. "What is a(n) {un,}reasonable {un,}lock delay?" (ms)

And then output parameters (n, salt/nonce sizes, factors) and password complexity requirements valid for implementation now.

It would also be nice to output an algorithm generated to forecast values needed X years in the future with similar guarantees.

[+] macrolime|3 years ago|reply
One way that I've many people using is to have a long random password stored on a yubikey that will be entered on long press, then you have a shorter password that you remember and type in.

So when you enter your masterpassword, you first type the part of the password you remember, then long press the yubikey to get it to enter the long static password.

[+] chickahoona|3 years ago|reply
If one is looking for an alternative, may I propose Psono? (I am the main developer behind Psono) It doesn't suffer from some of the reported issues and as such uses for example scrypt instead of pbkdf2 for the hashing of the masterpassword and the urls are for example also encrypted. Noteworthy its open source so everyone can take a look at the source code or ask questions in our discord channel. https://discord.gg/RuSvEjj
[+] hendersoon|3 years ago|reply
The real vulnerability with password managers is autoupdating browser extensions. That's the disaster on the horizon. They update on their own, all the time. You can turn updates completely off but otherwise cannot control this behavior.

Eventually, a password manager's development environment will be compromised and bad actors will sneak a trojaned extension in, submitting it to Google and Mozilla and Microsoft and the rest. Your browser will update to that extension and the bad guys will get everything.

Self-hosting won't help, your homelab running vaultwarden in a docker container not exposed to the internet is no protection from this at all. 2FA won't help either when the extension itself is your enemy, it'll simply upload your entire unencrypted vault off to the bad guy on IRC or discord or whatever.

(2FA will help on individual sites supporting it, assuming you don't use your password manager to store 2FA tokens too. They all support that functionality, but you don't do that, right?)

The only way to avoid this outcome, which again is inevitable, it WILL happen eventually, is to laboriously copy/paste passwords from a separate password vault program that is not configured to autoupdate.

The thought of actually doing that makes me cringe, so I'm still using Bitwarden. I know it's coming, and hope it hits another more popular password vault first so everybody gets wise and figures out some solution to this problem. I also use Firefox which seems to have humans reviewing extensions, at least sometimes, and is less popular than Chrome.

[+] fluidcruft|3 years ago|reply
I have been thinking about this and one way to resolve it is if the encryption data and the login cannot be linked without going through the server iterations. The reason this matters is because the salt for the hashing is the email address. Attacking the encryption key directly requires knowing the corresponding email. So denying attackers that knowledge adds to their burden.

If the customer/vault records can only be linked via the server side encryption the attackers with the vaulrs and list of user emails will have to test every email as salt (also reqires some care to ensure logs can't be used to correlate vaults and emails, but all the scenarios I've played out make me think this is possible). In fact I think they could physically separate the customer and vault databases entirely to different servers or datacenters.

Initially I thought this might be what Bitwarden does (it seemed pretty clever), but the database schema on github does indeed directly/explicitly link customers and vaults.

If the customer and vault datasets were independent, Bitwarden could further complicate attacks by filling the customer and vault databases with convincingly fake entries since the basic database attack surface would scale as the product of customers and vaults.

[+] nebulous1|3 years ago|reply
> In case you are wondering whether it is even possible to implement server-side iterations mechanism correctly: yes, it is. One example is the onepw protocol Mozilla introduced for Firefox Sync in 2014. While the description is fairly complicated, the important part is: the password hash received by the server is not used for anything before it passes through additional scrypt hashing.

> Firefox Sync has a different flaw: its client-side password hashing uses merely 1,000 PBKDF2 iterations, a ridiculously low setting. So if someone compromises the production servers rather than merely the stored data, they will be able to intercept password hashes that are barely protected. The corresponding bug report has been open for the past six years and is still unresolved.

Is this not always going to be a flaw with server-side iterations? And therefore knocks down the first paragraph's contention that it's possible to do server-side iterations correctly?

[+] Aicy|3 years ago|reply
I self-host bitwarden and you should too! You get the premium features for free when you self host

This is an excellent step by step tutorial that tells you how to self host it: https://www.youtube.com/watch?v=eCJA1F72izc

[+] dns_snek|3 years ago|reply
This is extremely irresponsible advice for anyone who isn't already skilled in securing their systems and keeping their software up to date. Skimming through that video, there's no thought given to securing the OS, "pi" account is effectively given root access (through "docker" group) with a default password of "raspberry", network access is unrestricted, there's no thought given to secure remote access (e.g. a VPN), there are no auto-updates for either the OS or vaultwarden, leaving you exposed in case of future vulnerabilities.
[+] ianpurton|3 years ago|reply
PBKDF2 iterations is the last in what should be a chain of defence in depth best practices.

It gives limited protection against a database breach.

Your password service should have as a minimum the following extra defences.

- Hardware encryption of the master password hashes.

- Breach detection such as poison records.

- Database access controls that limit the blast radius of an attack.

- All admins should require a hardware key to access the database.

I'm sure there are many more.

You can defend yourself with the following...

- by having a very random master password.

- 2fa everywhere

- password horcruxing - see https://kaizoku.dev/double-blind-passwords-aka-horcruxing

[+] gonehome|3 years ago|reply
1Password is excellent. More people would benefit from just paying for it.

Their secret key mentioned in the article appears like it was worth the UX tradeoff. They also stand out for other reasons too.

[+] andmarios|3 years ago|reply
I am not sure I get the flaw. The author says that the problem is an attacker only needs 100,000 iterations to get the master password hash, instead of doing the 100,000+100,000 iterations to get the master password and the master password hash.

Wouldn't though the master password hash be so long, that 100,000 iterations would be really hard to brute-force?

[+] rcxdude|3 years ago|reply
The point is it goes master password -> encryption key -> master password hash. The master password hash is only important if you want to download the database from bitwardan's server, the real valuable part is the encryption key, and the attacker is extremely unlikely to have the master password hash but not the encrypted database which they can use to check the encryption key.