JavaScript Cryptography Considered Harmful (2011)
nccgroup.trust
nccgroup.trust
On the other hand, that's a pretty narrow definition of "Javascript Cryptography". The article overlooks a bunch of other useful cryptographic things you can do in the browser, like end-to-end encrypted messaging. You can't lose a giant database of customer data if you don't have a giant database of customer data sitting around. Javascript can encrypt stuff before it even leaves the browser.
If you build your service this way, an attacker would have to carry out an active attack that injects bad code into your Javascript bundle. That's much harder than stealing a database, and even if it works, it can only compromises the users who log in during the breach.
So, no, the right kind of Javascript Cryptography is actually quite beneficial.
In the real world, most people run pre-built software, which is worse than this ideal. I agree that browser Javascript is worse still, but it's still better than sending secrets to a centralized server somewhere.
Security is a spectrum, not a binary on/off thing like this article tries to paint it. Things can still be helpful, even if they aren't perfect.
Just to head off as many of the standard arguments I can remember occurring whenever this shows up on HN:
* I'm talking about browsers-qua-browsers: while Javascript is not especially hospitable to cryptography the way, say, Rust is, it's not my claim that something intrinsic to Javascript is what makes cryptography hard. In particular: Node.js serverside applications and Electron clientside applications (with some caveats) are capable hosts for cryptographic features.
* Yes, Chrome extensions do complicate the analysis for the browsers themselves (of course: application providers don't want to do Chrome extensions, because it drastically cuts down user adoption). The story with extensions is not as simple as for Electron applications.
* No, WebCrypto doesn't make any of these problems better. WebCrypto provides primitives, but the interesting vulnerabilities in cryptosystems are in the joinery; a malicious server can still exfiltrate secrets even if you're using WebCrypto.
* It remains Hard to effectively assure the integrity of whole programs delivered to browsers, because there are too many ways to update an instance of content-controlled Javascript. The standard answer of "we'll just hash the js files" has never been credible!
App-level crypto in the browser certainly provides no added security to data transmitted over the wire, since (a) connections to back-end servers are already TLS-encrypted, (b) a breakdown of TLS implies the code running on the endpoint can't be trusted, therefore (c) assume data exfiltration when TLS breaks down regardless of other variables. I think this line of reasoning is just a restatement of your points above.
However, depending on how the back-end is set up, a zero-knowledge end-to-end encrypted vault would be impractical and even dangerous to decrypt in the cloud prior to serving it. Hence, in an end-to-end encrypted app, the chain of trust in client connections is anchored at the static file servers, the JS code they serve, and the TLS connection itself, not application servers -- the less trust app servers have to have, the better. I posit that it's easier to secure a static file server and TLS endpoint than it is to secure application servers. Furthermore, client crypto protects servers from ever seeing (or having to store/hash/cache) the whole symmetric key.
So client-side crypto can improve the security and trust calculus for server-side systems. In that case, a back-end breach of all but TLS endpoints and static file services would not expose user data.
If anyone can explain what's wrong with or missing from this line of reasoning, I am all ears -- please do!
In security engineering the main question is always "from whom do you want to protect it." If your assumed adversary can overtake both your TLS and deliver modified scripts, yes, the encryption in browser doesn't bring anything. If your assumed adversary is somebody less powerful like a passive listener somewhere the traffic is comes out of TLS, or somebody who has access to the data, but the data are already encrypted, then yes, the encryption can make a difference.
Or as one great thinker wrote for Usenix 2014: "In the real world, threat models are much simpler (see Figure 1). Basically, you’re either dealing with Mossad or not-Mossad." "If your adversary is the Mossad, YOU’RE GONNA DIE AND THERE’S NOTHING THAT YOU CAN DO ABOUT IT. The Mossad is not intimidated by the fact that you employ https:// If the Mossad wants your data, they’re going to use a drone to replace your cellphone with a piece of uranium that’s shaped like a cellphone, and when you die of tumors filled with tumors, they’re going to hold a press conference and say “It wasn’t us” as they wear t-shirts that say “IT WAS DEFINITELY US,” and then they’re going to buy all of your stuff at your estate sale so that they can directly look at the photos of your vacation instead of reading your insipid emails about them."
WebCrypto helps by providing a cryptographically secure RNG, that's not nothing.
FWIW I'm not trying to say the gist of the article isn't spot on, but I think the tools are more or less there these days to do the thing, even if it is absurdly easy to mess it up and there's no real good reason to try.
It seems like a clickbait rant more than something actionable or even really relevant. They even go on to say in the article you totally can do crypto "right" with JS it's just really hard. Isn't that known? Isn't that why we have libraries which are audited for security vulnerabilities by experts in the field? Isn't that true for literally _every_ language/runtime/vm ? I'm not saying JavaScript's number types and quirks aren't a huge pain in the ass but so is managing memory.
/shrug just my two cents.
In the years since 2011, we could have implemented high-quality side-channel-resistant JS crypto libraries (plus added browser features to allow storing secret data that wasn't accessible to the website, auditing JS source, etc.), or we could have just deployed SSL everywhere. The world chose the latter, and it was a better choice.
A lot of the article's other concerns are still valid, but there are a few new standards on the horizon which could eventually fix most of those and make cryptography in the browser viable, such as the Web Package standard. The Signed HTTP Exchanges standard's section on binary transparency is especially interesting for this use case: https://wicg.github.io/webpackage/draft-yasskin-http-origin-...
2013: https://news.ycombinator.com/item?id=5123165
Discussed at the time: https://news.ycombinator.com/item?id=2935220
I think articles like this get treated like they're referring to a broad category of activities, or making very broad statements, when in fact they're talking about a very narrow aspect of security. And to be fair, people do treat Javascript Crypto like it's the same thing as normal, native E2E encryption, so maybe that pushback is sometimes necessary. But this isn't a binary, black-and-white principle.
JS crypto is problematic in environments like the web because it is very hard to validate or pin the code that is sent to your browser (and for a few other reasons). This means that E2E crypto is not a good way of protecting yourself from a malicious provider. JS crypto does not remove your need to trust your host, and to trust your host's security.
It does not follow the E2E crypto has no uses at all on the web. It just means you have to be open about what benefits it does and doesn't provide. It isn't a silver bullet that will protect you everywhere.
"You can't simply send a single Javascript file over SSL/TLS. You have to send all the page content over SSL/TLS."
Is this a common problem in some way? It doesn't seem like a big deal unless you are trying to shave a few bytes off of your traffic.
Then let's encrypt happened and all that went out the window.
Not really. Modification risks exposure and some attacks are only possible after hours of compute time. For example if the HTTPS connection uses a cypher that's later found to be insecure then they can analyze the data pushed through the connection after the fact, but they can't intercept the now-closed connection. The NSA layers encryption for this purpose, and I don't really see the harm in encrypting with JavaScript as an additional layer in addition to HTTPS.
Plus, there are many places where passive attacks are much more likely than someone that's actually going to change your JavaScript. For example, many organizations terminate HTTPS at the perimeter of their network in order to monitor employee actions on the web. Using JS to encrypt is going to keep your secrets safer there, though some would argue that it's hostile to the orgs that downgrade the protocol on purpose.
Surely websites aren't designed in a way to take advantage of that, but I still don't see in the article a good argument why that is impossible - given that the local code is a carefully written (e.g. Stanford crypto library seems to be a good example of crypto JS code).
The relevant xkcd on this is this one: https://xkcd.com/2217/
Where "check my math" means the same thing.
The browser isn't trustworthy.