Building full stack of cryptographic protection for modern applications includes working with the modern web browser, of course.
However, through 20+ years of history of web browsers, we're at the stage where in-browser cryptography is still problematic, and best you can rely on is SSL. Which only protects data transport between you and server, leaving you hoping that you're good enough to go. Which is not always the case.
To deliver proper cryptographic operations into the browser our way, we've had to create C++ port of Themis, make it build in PNaCl way and build things around it.
Is in-browser JS crypto useless?
Problems with code authenticity:
- Same origin policy restricts bad code from directly injecting more bad code from third parties. This is easily bypassable.
- There's no way to audit code: random pieces of code can download more code from different places at any moment of page's execution, so 'View source' doesn't actually reveal anything.
- JS crypto code could've been simply replaced during an active MiTM attack.
- Code behavior relies on DOM - which can be modified by any other piece of code.
- Any function your crypto code depends on could be silently overwritten by any piece of content used to build the hosting page
- Browser cache is uncontrollable: once again, you never know which version of the code you run.
- What if we send all JS code via SSL? SSL is known to be vulnerable in some cases, yet, still, if you are transmitting anything outside SSL, attackers will use that least secure channel to hijack the code.
- Most JS crypto libraries supply only low-level primitives, requiring developers to compose cryptosystems themselves while writing browser code in JS. Not exactly the situation where you'd like cryptographic decisions to be made.
- Too many platforms with different JS engines, some of them will execute JS code in a different manner, too many platforms to support equal experience or equal security model.
- JS computations in the browser are plain slow compared to native code.
We are not aware of any really cryptographically secure PRNG in current JS libraries.
The worst thing is, there is no way to understand when and how the system was compromised as there are so many uncontrollable parts affecting code behavior... You could end up with the illusion of being secure, right until the point where you're not.
WebCrypto W3C standard and API
There is a movement for good, however: new WebCrypto API standard draft, partially supported by browsers. However, at the current moment it’s still not enough for us:
- It still lacks many important primitives, including questionable curve choice and doubtfully working Diffie-Hellman.
- Algorithm support is fragmented across browsers.
So, what we did?
Having to produce secure front-end web app as well, we chose to go another way: do a Chrome PNaCl-based port of Themis, and make our web application work with it. Covering half of web's users with a strong crypto is much better than covering all of them with a bad one.
Here's some part of the story of WebThemis:
- Introducing WebThemis
- Building Themis for PNaCl
- Building LibreSSL for PNaCl
- A WebThemis sample project: Building end-to-end secure webchat w/ Webthemis
In the next weeks, we'll summarize our experience of developing cryptography for Google Chrome, porting LibreSSL, building Themis for PNaCl, etc.