Selfhosted Vaultwarden feels like a step up from KeePassXC

But it is a trade-off between security and convenience

KeePassXC has been my password manager of choice for the past four years. It introduced me to generated passwords and entropy values, and it has managed to keep the core of my login collection safe and together. It has saved me a lot of headaches. However it has also been the cause of a few, so I went looking for a practical alternative and figured I found one in Vaultwarden.

If you don’t know Vaultwarden: It’s a password management server, written in Rust, that is compatible with Bitwarden clients. Bitwarden is the password manager advertised on every second podcast these days, after LastPass apparently dropped off the map (or maybe just focused on less techy customers?) In addition to it’s commercial cloud service form, Bitwarden is also available for selfhosting in the form of images on the Docker hub. It is, however, a pretty complicated setup – many containers talking to each other – and very much built for large organisations, not for selfhosters. Vaultwarden can run as a single container (if you’re happy with the default sqlite database) and is one of the easiest selfhosting setups I can remember doing.

Note the adjective “easier”, not “superior” or “better”, in my judgment. KeePassXC has a lot of options, some of which I’m sure are missing from Vaultwarden, some of which probably supply what I thought missing from it for but were buried to deep for me to find. In KeePassXC’s favour, there is something to be said for the security of an offline encrypted database file that you can never get with an online solution, selfhosted or not. You don’t hear stories about how hackers gained access to Joe Nobody’s database on his USB drive. You do hear stories about online password managers getting breached, though.

However, this post is written from the perspective of someone who has used a KeePass database for password storage for the past, roughly four years, across multiple clients, on- and offline and who just wishes it required less effort and manual maintenance.

Synchronization and “merge conflicts”

What I was most curious to test was this: Could Vaultwarden resolve what git terms “merge conflicts”? That is to say: When two local databases go off in different directions, can I still synchronise with the server and unite them without a lot of manual fiddling?

This is crucial because, using KeePassXC this kind of problem has been cropping up a lot. I will add a login on my work laptop, get distracted, forget to copy or upload it. Then I will add another login on my phone, and another on my home laptop. Putting it all together, now, is a right pain, because each of those logins are now inside of a big encrypted blob, and only one of those blobs can win in a file sync battle, eradicating the contributions from the other two. The only way to sort out the mess at this point, is to manually merge the files, usually followed by manually checking if all recent additions made it into the combined database (and trying not think too hard about conflicting deletions, moves, renames, etc.)

Yes, this can be mostly mitigated by putting the KeePass database onto Nextcloud. If I’m always online and all my devices have Nextcloud clients and I never open the same file on two devices at once, that is… That’s 3 ifs in case you weren’t counting.

How does Vaultwarden handle this issue? I tested it in three ways.

First, I synced two installs, both Firefox extensions, with the server. Then I added an entry for abc.com on one of them and an entry for def.com on the other. I manually synced the former with the server, then the latter. Inspecting the latter, I found that both entries were present.

That was too easy, I thought. What if both entries are on the same URI? So I repeated the experiment, only this time with both entries having abc.com as the value of URI 1. It didn’t make any difference: Both entries were present and correct after manually syncing.

This is probably not that suprising. The entries are not keyed to a URI, they just seem to be added to a long list with URIs as another list attached to the entry. Any one entry in Vault/Bitwarden can have multiple URIs associated with it and the password it stores. So even if a site sometimes logs me in on the main site, sometimes on a subsite or dedicated SSO domain, I don’t need to create three different entries with the same password. It follows from this that it wouldn’t make sense to use a URI dictionary as the main database. I also learned from this experiment that unlike a KeePass database file being synchronized using file sync, entry synchronization is atomic: Entries are synced as single entries, not as a new encrypted database blob.

The tests above show that Bitwarden can seemlessly merge lists with different components. My final test consisted of But what if one specific, existing entry gets changed in two different ways on two separate clients? E.g. I change the username for the entry to two different things. An entry can only have one username. It has to be one or the other (or the third, original). Can that be auto-resolved? I test it and for once, Vaultwarden is unable to fix stuff itself:

However, it’s an easy fix. Cancel the one change, I was in the middle of, sync with the server, then edit the entry.

Finally, it’s a bit unclear to me exactly what and when changes auto-sync – a question partly of clients and partly of whether or not ports are open for websockets. Still, even without seemless synchronization, you would be hard pressed to get it well and truly stuck. That is pretty much all I ask for.

URI matching

Another KeePassXC hassle has been getting either too many or not enough (i.e. no) password entry options. I have performed a search of what options KeePassXC offers to finetune it’s matching against URIs and these – under Browser integration settings – are all I can find:

The relevant settings are “Match URL scheme” and “Return only best-matching credentials”

And here are Vaultwarden’s options.

Match URL scheme, I suspect, is an option designed to prevent accidentally sending passwords over an unencrypted connection. It is almost completely irrelevant as most sites today are https-only and the few unencrypted holdouts are staunchly unencrypted. You will almost never run into a site that offers both.

That leaves us with a comparison of KeePassXC’s Return only best matching and Vaultwarden’s list. Given that KeePassXC tends to have the more advanced feature set and Vaultwarden tends to “dumb it down” for the sake of simplicity, this feels a bit topsy-turvy.

Vaultwarden matches with base domain by default. So an entry registered to brokkr.net will also match www.brokkr.net and games.brokkr.net as well as brokkr.net. Switch to host based matching and now only entries for “games.brokkr.net” match games.brokkr.net. Starts with allows for crude scheme matching and with Regular expression only your imagination sets the limits. Vaultwarden lets me set a default matching option and override it for any one entry. E.g. I generally prefer Host based matching because I use subsites for different applications with different logons but some SSO solutions spread themselves over multiple sites under a single domain. For those I then choose to match Base domain.

I think, that KeePassXC by default matches against the base domain. Return only, I think, prioritizes a complete url match, secondarily host matching, fall back on base domain. It mostly works. I definitely prefer the finegrained control of Vaultwarden, though. If for no other reason than I am able to understand and explain why I am seeing the matches I am seeing.

Password entry

Once a login has been matched or selected, how well does the application manage to insert the matched login and password in the correct fields? Mostly, this is binary for any one site: Either the application manages it or it does not. Still, I would hand out bonus points to Vaultwarden, if it didn’t fill out the registration fields in addition to the login fields on Hacker news.

This all comes down to how well the application understands and interfaces with the login pages’ document object model. I didn’t rigorously test KeePassXC and Vaultwarden against each other on the same sites so you will have to trust me when I say that Vaultwarden feels like magic after using KeePassXC. Especially on sites where the password field is only revealed after entering the login, e.g. The New York Times, KeePassXC would trip up so regularly, that I just got used to copy-pasting without even trying to push the insert button. Vaultwarden has so far entered the username and password without fail on all sites.

KeePassXC does have a feature that allows you to help it understand the page. I can tell it: This is a username field, this is a password field, this you should just ignore. It’s a good idea. If for whatever reason the default algorithm fails on your favourite site, add a manual fix once and it should work. Except it doesn’t. Or maybe I’m doing it wrong. I have lead KeePassXC to water many times, and it still refuses to drink.

Vaultwarden adds a little, quick fast-typing animation to it’s password entry. It feels like showing off.

Password generator

For all the KeePassXC fans out there, looking for a win for KeePassXC, here it is: The password generator in bitwarden clients is facepalm levels of bad, if you’re coming from KeePassXC. If you come from making up passwords using former addresses and pet names, sure, it’s an improvement. If not, well, for something so central to a password manager, it seems like an afterthought.

Now of course, you can enter any password you want in both clients, so you can just use uuidgen or openssl or bash-head-against-keyboard as a source of passwords. If you’re lazy like me, you expect your password manager to come with a password generator, and a good one at that. This is a good password generator:

KeePassXC allows the user to individually add 11 groups of characters, including a user-defined one. It will calculate an entropy value for you as well, though I’m not sure of how much faith I should put in that (I think that entropy is a function of the character repertoire and password length but the KeePass value changes with the characters picked, despite the repertoire and length staying the same).

Here’s the generator included with Bitwarden:

Same overall options, except… four predefined groups. Am I still statistically safe using [A-Za-z0-9!@#$%^&*]{20}? Yes, in all likelihood. But I could probably get away with shorter passwords if I had more options. See the 141.84 bit value in the first picture? That jumped up ~35 bits as soon as I added the custom repertoire of æøå. Is that an exact, scientific measure of how much safer I am against brute forcing? Of course not. But it can still be reliable translated as “a shit ton”.

Those keys are a lot easier to press for anyone with a Nordic key layout than, say ^. To target them attackers will typically have to increase the dictionary to all of latin1. (Incidentally, the “extended ASCII” repertoire in KeePassXC looks like it’s actually all of latin1… which is not particularly useful as nobody has all of that on their keyboard and would have to rely on composing characters, a somewhat unreliable means of producing passwords). Obviously, other people with other non-US keyboard layouts will have their own ways of easily making their passwords much harder to bruteforce at little to no incovenience to themselves.

Several of these issues have been raised with Bitwarden. The main concerns seems to be a) some sites don’t support anything but these characters and b) “all of unicode” would mean plenty of “ambiguous characters” (I suspect that currently, the “Avoid ambigious characters” option just blocks LATIN SMALL LETTER L and DIGIT ONE). Neither of which is a good reason not to allow knowledgeable users to add custom classes.

Though the concerns are real – above all, don’t leave the non-techy customer high and dry – the client here still feels antiquated, US centric and poorly thought out.

Conclusion

As I said at the top, Vaultwarden makes life easier. It’s easier to maintain one database across devices. It’s easier to match sites. It’s easier to get the login information into the relevant fields.

Convenience and security do, however, not often go hand in hand. I don’t like it’s password generator though that could so easily be fixed. And while it’s unlikely that a selfhosted, one-man, no-index-no-follow site will become a likely target, it is a lot more likely than someone getting hold of and unencrypting my offline keepass database.

So it’s a tradeoff. I think I’m okay with that. I’d definitely recommend the switch for anyone but the most security anxious.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.