-
-
Notifications
You must be signed in to change notification settings - Fork 1.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement Native Messaging for browser extensions #287
Comments
You're not the first to suggest better and more secure browser integration (#259 and #88). The problem is that it really is a lot of work and we can't also maintain and support two browser extensions alongside KeePassXC. If someone steps forward and builds those browser extensions, we may implement support in KeePassXC for it, but the other way round is just not possible. |
Would the database / password / keyfile combination live in the browser extensions? The way I see it, a new host process is spawned every time a message is sent from the extension, so there's no way for the host to preserve some state, it has to be passed by the extension every time a message is sent. |
The host process is started once when the browser extension calls There is a good question about what to do if there is already a running KeePassXC. The simple answer to let both run, and rely on DB merges. The more complex answer is to have a stub process for KeePassXC that tries to connect to a running process via IPC, and if there is none, starts one. |
This implies that the opening of the database (asking for database filename / password / keyfile) would take place in the chrome extension. is that correct? |
I suppose it would be possible to simply raise an existing KeePassXC instance. Having password and keyfile inside the browser extension is out of the question. |
Yep, my thought was similar to what @phoerious said - KeePassXC could bring itself to the foreground if it needs the database unlocked. |
I'm currently experimenting with this. At this point I have a fork of chromeIPass that connects to a python host and sends a version query request and receives a reply (Settings -> About shows KeePassXC version instead of KeePassHTTP version). So it's a start. Because KeePassHTTP is not needed at all (or HTTP Requests) the whole protocol needs to be rewritten. Takes a while. The next big step is to connect to a dummy database and receive a hard coded entry for a single page. |
@varjolintu, do you have a branch/repo where we can check how you do that? I'll be very interested to see the code! Thank |
@GuilloOme, not yet. I'll make a public fork when I've done some more experimenting. |
At this point I have a "working" way to deliver a generated password and multiple credentials to the browser tab. Also filling the password works based on the username entry. But still, some work needed before a public fork. I was wondering if any encryption is needed between KeePassXC and the browser extension? Is Native Messaging really secure enough for transferring the data as plaintext? |
In my opinion, yes. Here's my reasoning: If there is software on your machine that can intercept stdin / stdout, or wrap KeePassXC in a fake binary that will proxy stdin / stdout, that software already has sufficient privilege to read your KeePassXC passwords directly from memory, or present a fake version of KeePassXC to collect your password and keyfile. |
According to our devop at @delvelabs, depending of the secure level of your OS, it could be very easy to read what is shared between process in the same userland. Since it is not possible to make sure that an OS is safe enough, it should be encrypted… And from here, start the debate around the key management between processes 😉 |
@GuilloOme: The question is: Is it easier to read stdin/stdout between processes than it is to read another process' memory, or to wrap another binary? |
As I understand, there is 3 ways that we could access to what we want to protect (ie. readable password). Assuming we are in the same userland (no privilege escalation needed):
Is there an other case, we would want to cover? The next concern will be key management… |
The key management and transferring the data between the browser extension is not an easy task. One way to do it might be:
Pros:
Cons:
|
I think the most important thing here is authentication over encryption. Encrypting the password while sending it to another process doesn't make things much more secure. What's very important though, is that once your database has been unlocked, only a privileged (authenticated) process can request a password. We probably need some sort of challenge-response protocol for that. |
For the secure session management and the crypto, I was talking with our crypto guy here at @delvelabs and he were recommending trying using a lib/protocol like libsignal-protocol made and tested against this kind of concern availlable in JavaScript and C (never tested on our side throw). But still if it's too much work, we should drop the encryption (for now) and focus on authentication. As @phoerious was saying if every request are blindly accepted, no need for an encryption layer… The way the current implementation of KeePassHTTP behave seems correct: requesting a user action through a dialog for each request and a one time authentication for the browser extension. |
The main problem with KeePassHTTP is that the key is randomly generated by the client (I don't even know if CSPRNG is used here) and sent base64 encoded plaintext to the KeePassXC server. I kind of like @varjolintu proposal and I came out myself with a similar idea some week ago. Some discussion point:
This will authenticate the client and can address MitM and replay-attack (since the nonce is randomly renerated everytime and the attacker can't guess the nonce). Sorry for the wall of text. Also now I remember this from last year https://medium.com/@rosshosman/1password-sends-your-password-across-the-loopback-interface-in-clear-text-307cefca6389#.kva4n6ofq |
I disagree with this ranking of difficulties. Instead, I would ask where the security boundaries are. For KeePassXC, I would say that the defensible security boundary is "code execution on the local machine." If an attacker has local code exec, there is nothing KeePassXC can do to defend against it. Adding a layer of encryption or authentication to local process IPC merely adds complexity and UX friction, without adding significant security. |
There's a development version available at: chromeKeePassXC The implementation is almost identical to chromeIPass except JSON data is changed to lower case. The random key generation is using tweetnacl-js and I'm also considering if it would be easier to use secretbox to encrypt the whole message instead of transferring the message in plain text with encrypted elements. This version is far from perfect, but it is a start. To get this to work needs changes from KeePassXC side. Maybe it would be easiest to implement receiving a test-associate message first. The .json file should be installed to following locations (edit the path for KeePassXC or test client):
|
Some major changes made to the extension:
|
What do you mean with
I personally don't really like adding many encryption algorithm all for different things. This will make HTTP code more complex and KeePassXC won't be compatible with KeePassHTTP anymore, unless we keep both new and old version |
In chromeIPass databases used with the plugin are stored with the id, hash and the key. In the future, only with id and hash because keys are always generated each time a database connection is being made with KeePassXC (or test host). In chromeIPass the JSON message itself was unencrypted but each element was hashed or encrypted with AES. So instead of encrypting the items one by one only the message itself is encrypted. In this case there's actually less encryption. And yes, this breaks the compatibility with KeePassHTTP but I think the compatibility remains with few changes to the KeePassXC side. I will try to test this by myself. |
I mean, we need to add new code for encryption algorithm in KeePassXC since chromeIPass uses AES (and we already needs it for decrypting the database). What algo are you using for NaCL box? |
It uses the default, Curve25519-XSalsa20-Poly1305. I suppose it's pretty straight forward method to just include libsodium to the project. |
At this point I already have a working Qt test host with libsodium. The next step will be a test integration to KeePassXC. I'll try to maintain the compatibility with KeePassHTTP. |
It's already possible to connect chromeKeePassXC to a database, use the password generator etc.. Still need a lot of work. But it's moving forward in tiny steps. You can keep track of the process through these branches: |
Currently you can use the following releases to test the Native Messaging feature: Be sure the extension ID matches with the installed JSON file. See this guide for further information. All the chromeIPass features are now working. The extension itself is not yet finished (mostly the popup status display) and the KeePassXC side also needs some work. If you want to build the branch by yourself use Any comments or suggestions are appreciated. One big question is the boost dependency. Only library needed is the boost_system (for asio). If boost dependency is a big no it's always possible just include the plain asio c++ library instead. |
Latest releases: |
Thanks for the work. We should review this soon and then decided to how to proceed with upstream merging. |
I'm also trying to make the extension Firefox WebExtension compatible. The extension already loads but the functionality is still limited. Please notice that I'm using Firefox Nightly for testing the extension. The stable version is not up-to-date enough. |
Latest releases: The browser extension works with Firefox (nightly) also without any major problems. The KeePassXC branch is now merged with develop (was behind around 400 commit.. oops). The single instance feature didn't change the way Native Messaging works, and this is the biggest "turn-off". The KeePassXC process much be opened with the browser instance. If it is open before opening the browser Native Messaging cannot find the KeePassXC host. This is really bad, and it what makes it worse is that when closing the browser KeePassXC is closed also (and it doesn't even prompt you for saving unchanged stuff.. just closes). But if you use KeePassXC just with a browser, this almost works as it should. Edit: |
The only fix for this is to create a small application that acts as a proxy between chrome/firefox and the running instance of keepasxc. This might be relatively easy to do, the proxy would simply pass the stdio to the running keepassxc instance as-is. |
The problem is that Native Messaging needs to launch a new process. It cannot connect to a process that exists. So QProcess is out of the game. Maybe QLocalSocket could be the answer. I should definitely investigate this approach. |
Yah, the proxy application gets created at-will by the plugin while the main keepassxc instance stays running. |
I have been experimenting with a proxy application which uses UDP sockets on localhost to transfer messages. It already works pretty well but still needs some work. The next version of the browser extension will be renamed to keepassxc-browser. One good reason for this is that Mozilla doesn't allow browser extensions which carry a name of another browser. |
@varjolintu Nice, you are doing a great work! 😉 |
From #259
...same here? |
Yes. Let's close this. Many information here is outdated. |
Chrome and Firefox support Native Messaging, which is a way for browsers to communicate with native processes more securely than using an HTTP server on localhost.
The Chrome documentation describes it well, but in short, the native application provides a manifest file at a well-known location, listing some information about itself and the set of extensions that are allowed to access it. When the extension requests, the browser will start up the native process, capturing its stdout/stdin, and pass JSON messages to and from it.
This would require significant changes on both the KeePassXC side and the browser extension side, but it would have two main advantages:
The text was updated successfully, but these errors were encountered: