This isn't actually end-to-end encryption, right? You have to trust the server not to corrupt the JS context to exfiltrate secrets. If that's the case (if I haven't misread something here), what is this buying you over just TLS?
It's end-to-end in the fact that it's encrypted and decrypted client side with the server only seeing ciphertext. With TLS, third party observers see ciphertext but the server sees plain text.
There is an attack vector that the server offers a malicious JS file (something which any web based encryptor such as Protonmail is also "vulnerable" to) however this is also possible for other types of application too. App stores can send malicious copies of Signal (both for initial install or (auto-)updates). Future Thunderbird updates can bypass OpenPGP encryption. Dependencies can have malicious backdoors added to affect core encryption libraries.
Trust has to be accepted somewhere along the chain, it's up to you where.
I didn't ask an abstract question. I'm asking specifically: what can you accomplish with designs like this that you can't accomplish with TLS and serverside encryption? When you think about that, work out what the threat model is. Yes: with serverside encryption, the server briefly sees plaintext, or can record keys. But with clientside Javascript encryption, the server can exfiltrate keys and recover the same data. The question is specific: what's the advantage, in what threat model?
Okay we can go through a threat model. We have a user, a service and an attacker.
Scenario 1: Attacker external to service
With TLS and server side encryption (generally at rest), if an attacker breaches the service they will have full access to all user data. The server has the encryption/decryption keys.
With client side encryption, if an attacker breaches the service they have access to many encrypted blobs that they need to decrypt. If the attacker wants to do this they have to create and plublish a malicious JS and update any resource integrity before waiting for the users to use the malicious version and even then will only get a subset of user keys.
Scenario 2: Attacker internal to service
With TLS and server side encryption, a malicious employee can generally get access to the unencrypted data. Once again, the server will have a copy of the key. Whether by accident or on purpose, plain text user data can be leaked into logs, dumped into backups etc.
With client side encryption, the attacker only has access to ciphertext. Again, they would need to publish a malicious library, bypass any resource integrity at the same time and wait - remaining undetected - for every user to log in so their keys could be siphoned away.
-----
It may be the case that the server needs access to plain text data in which case a more complex approach using a unique user key pair where the public key encrypts the data after processing so the server cannot decrypt it could be utilized. But even then, there will still need to be some JS sent to browser for that logic.
If there is no business reason for the server to see the plaintext data, client side encryption should be preferred.
No. In scenario 1, with TLS, an attacker gets access only to data corresponding to incoming requests. The same thing clientside Javascript cryptography code does to push secrets out to the client (either by deriving keys from memorable secrets or using local storage) works to store secrets serverside encryption can use; lots of encrypted cookie systems have been built to do this.
Your scenario 2 analysis works by suggesting that attackers can't easily subvert the Javascript contexts of clients (it mentions for instance "resource integrity"). But every request for any resource that alters the DOM or loads code allows an attacker to pull this off; it's the premise of the attack. This is an even weaker case for browser JS crypto.
I think the big premise mismatch we have is that you're assuming I'm saying "just use TLS and store keys on the serverside".
I feel like discussions about WebCrypto always fall apart in arguments over abstractions, like software update versus HTTP requests. But I'm saying, it seems like you can literally just skip all the clientside cryptography, stuff keys in cookies (or whatever), and do all the encryption serverside, and end up with the same threat model, which to me is telling.
I don't think people are crazy for pushing back on this. People smarter than me disagree about it. I wonder if David Adrian wants to take a swipe at this argument.
Ah - you might be right that there are some crossed wires here as I was imagining a "just use TLS and store keys on the server" scenario.
Could you correct me please so we're on the same discussion ground? Where does encryption happen and what mechanisms are used to ensure the security of keys?
It may be easier for an insider or compromised server to add a silent exfiltration functionality to server code, than to additionally compromise the frontend build, add a side channel by which the client could transmit the secret to the server or to a third party, and exfiltrate the data itself, all without detection. Defense in depth!
Oh, and a deactivated account, where no client with secret access ever gets updated or executes code again, will never leak its secrets, regardless of level of (pre-quantum) compromise of the company. Useful for limited-time communications that need to be private from sophisticated adversaries in perpetuity.
Not to mention that it signals commitment of your company to data privacy, which may deliver value in and of itself.
I don't understand the first point as a claimed security level with a specific threat model. The second point, about deactivated points, is equally true of serverside encryption --- again, assume keys stored clientside, but encryption code run serverside (in fact, it can be true in applications that don't encrypt at all).
If I have a 0day for your backend stack, or you fail to upgrade a dependency, I might get RCE on your backend server and install an exfiltration system, but I would not necessarily be able to pivot to changing the frontend bundle on the static CDN without compromising the CI/CD and code review system, which (hopefully) uses isolated credentials and has strong audit logs. A threat model where even a persistent or long-running infection on backend servers allows user content (if not metadata) to remain opaque can be useful.
Server compromise is one of the threats this help manage. In your "just TLS to the server" scenario, that means all data is now instantly readable to the attacker. When all data is encrypted with keys only known to the client, the attacker first needs to take active measures and wait for everyone to log in, which may be visible to attentive clients (think reproducible builds, or the same way that someone might reverse engineer WhatsApp to see if they really did implement the Signal protocol correctly)
I've also been the victim of an attack where passive interception was feasible but not active interference. Everything they could use my session token for, they did, but my password was client-side hashed and thus the admin panel (access logs showed attempting to reach it) was safe because it required entering the password again
As a last example, I don't know what binary Signal gives me, but it gives me piece of mind that it requires colluding with Google to target someone specific, so they effectively give everyone the same binary and any backdoors are visible to all at the same time. I really like client-side cryptography as compared to the server being one big black box we just have to trust
Iff you are referring to https://news.ycombinator.com/item?id=39976605 (providing a link to what you're talking about might have been more fruitful), you've not read most of my reply. They mention only data at rest or an implementation bug whereby the server stores all keys at rest in an accessible format (both a similar scenario), which I now understand you say we can still have with server-side crypto, but they don't mention and you don't seem to reply to the transparency aspect that a lot of my comment is about
A pointed question. Under threat models where you trust (or have verified) the code being executed, this allows you to use untrusted storage (e.g. cloud databases, S3, etc.) without worrying about passive attackers being able to read your data.
Using TLS and server-side encryption, a passive attacker could install a shim to intercept data.
In practice, one usecase of Minibone would be open-source electron-style web applications where you have the necessary code transparency AND signed code versioning.
Another would be self-written applications (assuming you trust yourself).
Another might be closed-source internal tooling (assuming you trust your company) that's hosted on cloud infrastructure.
If I've overlooked anything, please do let me know.
I have no trouble at all with libraries like this for Electron apps. In fact, I'd go a step further and say I concede the argument for Chrome Extensions and the like. It's content-controlled code that's problematic here.
Maybe you trust the server to serve legit JS (or have some other mechanism to ensure it, like content addressing e.g. IPFS) but you don't trust the server not to leak/log your info by mistake if it was processed in the server.
> You have to trust the server not to corrupt the JS context to exfiltrate secrets.
Yes, you do have to trust the web server(s) in that way so it isn't E2E in that sense. Though with native code E2E you need to trust the source of your app (and subsequent updates) similarly so it isn't entirely different.
You are still protected in cases where a third party attacker gains access to the data but not access to subvert the web server(s) so they send code to perform exfiltration, so there is more protection than with just TLS (or TLS plus plain encryption-at-rest).
Whether this is useful or pointless is going to be dictated by your threat model, though I'd agree it might be worth having some sort of disclaimer stating that the E2E promise might not be as solid as for other systems. Thought said promise may not be as solid elsewhere either: have you verified WhatApp's code at all? (not picking on them intentionally, just plucked them out as the first example that sprang to mind, the question is more valid with less well known services that are less likely to have any worthwhile independent checking/oversight).
The vast majority of users have automatic updates enabled for their native apps which makes the security properties very similar IMO.
And if you turn off automatic updates then you don't get vulnerability fixes. So you're really at the mercy of the people providing your software updates even if we like to pretend that you're not. In the event of something like a world war, theoretical concerns like these would quickly turn into actual concerns.
Having automatic updates enabled is not in fact the same thing as reloading all your cryptography code every single time you make a transaction. For a very recent and clear example of why, look what happened with xz, and note how you did not in fact get owned up (I'm sure someone did, but the odds are in my favor on this guess).
Not by the specific xz hack that was found. But I guarantee there are a whole lot more that haven't been found. You can't declare victory because we discovered one hacker. Effectively auditing updates for malicious code is impossible both in theory and in practice. As soon as you accept updates you're vulnerable. And if you don't accept updates you're vulnerable because it's impossible to verify that your initial install had no vulnerabilities, either intentional or accidental.
I agree that more frequent updates make a difference, but that difference can easily be in the positive direction too. And I think the overall difference is really not as big as you suggest.
Perhaps it would be useful to have something like a certificate transparency log but for the application code, so it could be retroactively audited on suspicion of foul play, and attacks that supply different updates to different users could be detected by third parties. This would be useful for native apps too.
> automatic updates enabled is not in fact the same thing as reloading all your cryptography code every single time
It is absolutely the same thing as potentially reloading all the code on a regular basis. If you aren't monitoring the updates then "a regular basis" might as well be every time. Turn automatic updates off (but notifications on) on an android device and watch how many apps sometimes update a few times in a short period.
There is a minor gate in that there will be some cursory review of an update delivered via an app store, where a web server can give you updates literally every session or potentially every request, but that cursory check is not enough to give the level of assurance over js from a web server that some take.
> look what happened with xz, and note how you did not in fact get owned
The xz thing could easily have affected a great many people had it not been accidentally discovered. It shows why the app store model could be a concern as much as the js-from-a-web-server app model, not an example of how such gates truly make a difference. It likely would not have been picked up by the screening done in new app releases in a store, and likely nor would some hidden-ish exfiltration code.
The slow update process whereby changes upstream go through testing periods in "unstable" bleeding edge distro variants before getting into the officially stable ones only made a difference by chance. That upstream-to-enduser latency is much lower for E2EE apps in app stores - I'd argue that the risk is much closer to the web server model than the Linux distro model, and the distro model probably very nearly didn't help.
Some people finally are -- and, frankly, all of them should be, though that's another argument -- building web applications where the code for the web application itself is being loaded off of a decentralized system via a newer protocol or a gateway that they can control and which verifies the hash of the site being loaded. Also: even for services like WhatsApp Web, there are browser extensions such as Code Verify that provide most -- if not "all" or even "more than" -- the benefits you supposedly are getting by having your automatic updates re-distributed via a third-party package manager.
Think of it this way: if your database gets breached, your app won't leak user data if your users aren't all targeted by active attackers. It's not a substitute for transport security.
If active attackers are an important part of your threat model, you do want to assure the integrity of the payload - and you can ship Minibone in things like Tauri (or Electron) apps, like we do at Backbone.
"If your users aren't targeted by active attackers" is doing a lot of work there, right? Because you can get that same level of security without an "end-to-end encryption library" --- just encrypt rows, and store the keys in localStorage, or (ick) by deriving keys from passwords, the way this seems to. All the cryptography can live on the server, and the keys can be pushed out to the client. Now you need an active attacker in order to mass-exfiltrate the database, which is what you're going for, right?
But again my real point is just that you've misnamed it. This isn't E2EE. The whole reason we have the term "E2EE" is to capture not trusting the server to manage cryptographic secrecy.
I'm not sure what you mean - Minibone's entire purpose is to allow you to not trust the server with users' plaintext data.
Naturally, you DO need to run Minibone in an environment that's not compromised, but even if you're concerned about TLS (and there can be valid reasons to be concerned depending on your threat model), web apps can and do run in places other than the browser - that can guarantee the integrity of the bundle.
In any case, for most use cases, database compromise is much more likely than active attacks from APTs that can break TLS.
Right. But you do have to trust the server, unless you factor out active attackers, who can corrupt the JS context and exfiltrate secrets. If you do that, though, you don't need the clientside cryptography anymore; you can use standard, non-cryptographic browser mechanisms to make the client a root of trust for the data, but run all the cryptography serverside. (Apps have been doing this for decades, for what it's worth). Obviously, you have to trust the server when you do this --- but only because of the threat of active attackers!
In my opinion, if someone can break TLS such as getting your private keys then they are likely also in a position to poison your E2EE code.
I use E2EE on IRC but the code is entirely separate from the IRC server. irssi-otr using OTR Off The Record library. Provided the IRC admin does not monitor private messages and kick me off for sending text they can not read, I can have private communication with any of my friends on any IRC server knowing full well that the admin can not read it. No amount of hacks or updates to the IRC server could possibly intercept and decrypt my messages regardless of whom compels the admin to make every effort to do so. This of course makes libotr a juicy target but that's another topic similar to xz but thankfully there are not yet a significant number of people using OTR, yet.
This leaves the only remaining option of "obtaining secrets by large wrench in person" but there are countermeasures for that as well.
What meets your e2e standard? You can always corrupt the client, even an update in a mobile app. I agree JS is more
vulnerable to extensions attacks or XSS or supply chain of some other dep you included.
The team behind this project (read: we) developed an expansive SDK for multi-user collaborative apps, including realtime docs. We use it to power many of the features of https://backbone.dev/
The multi-user scenario is significantly harder to get right without running into nasty vulnerabilities. We plan to write more about how we built it and what to look out for.
How you can tranform minibone adoption into a sell point? A non technical end user is not able to verify that an specific user is using an e2e library. It's probably limited to FOSS
It's much more bare-bones. Minibone exposes a more approachable and misuse-resistant higher-level API including support for things like opportunistic key rotations and groundwork for forward evolution!
- If I don't trust you with my data, why would I trust you to serve me the library I use to encrypt my data?
- I don't think it's possible to restrict parts of your JavaScript env from a server, so even if I get minibone from a CDN, check the hash, and encrypt things clientside the unencrypted stuff lives somewhere, or the server can setup hooks to grab it before I clean it up, etc.
- Apps that want "security after TLS" just encrypt it serverside, which is generally better. This is fine because your users have to implicitly trust your servers.
I'm also unclear on how key management works; is it managed serverside?
> If I don't trust you with my data, why would I trust you to serve me the library I use to encrypt my data?
Because trust has to be given somewhere and my business would likely fail if I'm telling you it's encrypted but actually it's not.
Plus, if you were really concerned you could open up the developer tools, network tab and see the communication to the server and validate that it's only sending encrypted data that you know the server can't decrypt.
> the unencrypted stuff lives somewhere
Most likely the plain text will only live in-memory in the clients browser (depends on the implementation of the software using the library though). Unless I've mis-understood your concern?
> Apps that want "security after TLS" just encrypt it serverside, which is generally better
Why is this "generally better"?
With client side encryption I can see my data, the server and any third-parties cannot. With server side encryption I have to send plain text. TLS protects this from third-party observers but anyone server side - now or in the future - can access my data. There is also the possibility of future breaches as encryption at rest stops at attacker running away with a harddrive but does not stop an attacker accessing a running database and dumping all the decrypted contents.
I think the idea is that the server immediately encrypts your data with a key you provide, deletes your key, and keeps your data encrypted at rest. You're trusting the server to do the last two things, like with client-side encryption you're trusting the server to send you non-compromised encryption code and to not exfiltrate your key. This seems much more equivalent, and in either case a compromised server can get your data as soon as you next access it.
> Because trust has to be given somewhere and my business would likely fail if I'm telling you it's encrypted but actually it's not.
I think in this case you'd probably want to control the keys, right?
> Plus, if you were really concerned you could open up the developer tools, network tab and see the communication to the server and validate that it's only sending encrypted data that you know the server can't decrypt.
You can't realistically do this every time; it's an opsec fail waiting to happen. That's why we hash dependencies, use TLS, etc.
> Most likely the plain text will only live in-memory in the clients browser (depends on the implementation of the software using the library though). Unless I've mis-understood your concern?
This is the "active attack" scenario, where the server is trying to get stuff from your browser you don't want it to have. The authors say that's not part of their threat model, but that's not super satisfying when companies of all types and sizes are suffering huge hacks these days.
> Why is this "generally better"?
Well for one you don't have to write and maintain a huge-ass JS encryption library.
For another, implementation and maintenance is much, much easier. You don't have to:
- (write a clientside JS encryption library, but already mentioned)
- write serverside validation that the data you're receiving is in fact encrypted the way you expect (you can only do so much here besides)
- manage clients using old versions of your library with different sets of primitives when you want to evolve
> TLS protects this from third-party observers but anyone server side - now or in the future - can access my data.
You just solve this with regular encryption. But if at any point you're trusting a server, e.g. you're loading JS from it (meaning using it at all for 99% of users) or it's storing your keys, you don't have E2EE. The whole point of E2EE is that it's secure in a hostile server scenario, i.e. active attacks.
This is just defence in depth. But I agree server side feels better for this. OTOH that means it is not really e2e as there is some machine with your unencrypted data on it ready to be hacked.
The ideal solution would be a web api. Seems like this is only available low level with a “don’t use this to roll your own” disclaimer. What would be ideal would be a string->byte[] function in the web api that encrypts (and one that decrypts) with key management delegated to the browser.
> But I agree server side feels better for this. OTOH that means it is not really e2e as there is some machine with your unencrypted data on it ready to be hacked.
It's true this is a step up from "non-encrypted at rest", which has been pretty troublesome. But the whole point of E2EE is to defend against a hostile server. I can't understand the point of releasing an encryption toolkit, labeling it as "implements E2EE", but then ruling out the very thing E2EE is supposed to address from your threat model. The only reasonable thing to conclude is that this isn't E2EE. I'm not saying it's dangerous, or even that it's worthless, just that it's mislabeled.
This looks... Interesting and also weirdly suspicious. It's "made by Backbone". Backbone appears to be an enterprise security startup (?) but it's unclear because the website tells you almost nothing about the companies history, finances, or who makes up the company.
The committers appear to be "Backbone Authors". The organizations membership is not visible.
With something like this, trust is vital. I need to be able to trust the code now and into the future. For trust, transparency is key. And this project has zero transparency.
For all I know, this could be a state actor trying to lay the foundation for future backdoors.
I'm one of the authors. We built Minibone as a community contribution because we realized how unnecessarily vulnerability-prone E2EE app development is today - after seeing app after app repeatedly making the same mistakes.
Minibone is an initial attempt to address this challenge in the single-user setting (that allows a concise and easily auditable implementation).
Jumping on this, I've also noticed you don't seem to have an obvious "Terms and Conditions" or "Privacy Policy" on your site.
It's also not immediately obvious to me where the company is registered or info about the people behind the company.
For a security focused company these are all things I would expect to be rock-solid and as transparent as possible for the initial due-diligence when evaluating services like this.
> The committers appear to be "Backbone Authors". The organizations membership is not visible.
This is slightly insane. How can they release something as Apache License if they aren't even giving out the name of the developers? Exactly WHO is licensing this source code?
There are many open source crypto libraries and it's probably not the wisest to use one authored by anonymous developers
If the Minibone repo turns out to be malicious I don’t think it makes much of a difference whether they are committing as one anonymous user, or as 12 fake people.
Tracking the fake people still give some information (for example, the more sock puppets, the harder it is to simulate discussions in issues, PRs, etc)
There seems to be a lot of skepticism in the comments but I can definitely see a use-case for this (I have no relationship to the project).
Ultimately, plain text data should never reach the server and the server will never have access to decryption keys either. Row level encryption; encryption at rest etc. is not the same as in those cases the data arrives at the server in plain text which can end up in logs, can be directed to other parts of the business or in invisible changes the server may just stop encrypting the data.
By encrypting client side, I - as a user - can be sure that my data can't be mined, analyzed or leaked.
I acknowledge that there is the poisoned binary attack - serving malicious javascript files to future visitors - but this may happen somewhere along the supply chain for any application. Whether it's an app from an app store (e.g. Signal) or a desktop app (Thunderbird + PGP) at some point updates are provided to client apps and as we have seen recently, even dependencies to these apps are vulnerable. SRI and maybe clearly showing the version of encryption library being used would probably go a long way. Services such as Proton also rely on JS delivered to the browser.
In short, a lot of applications could benefit from adding a layer of encryption to their data. The truly paranoid may not be happy putting their trust in a javascript blob but the vast majority of people would benefit from having a little extra privacy-by-default in their lives.
Lack of streaming support in the API makes this DOA for many use cases. Fully buffered APIs like these are an unideal abstraction and should be avoided for any large or streamed resources.