Reading the news on Heartbleed in the mainstream media these days got me thinking. It's hard enough to grasp the consequences as a technical person, but trying to explain to my girlfriend why she might want to change the passwords to all of her favorite sites made me think if things couldn't be different.
It's very trendy to criticize JS crypto. And while some arguments are valid, more often than not they are made in a vacuum and without context. When discussing security mechanisms we should discuss what we're trying to protect and from whom. For web apps I see two main categories:
Services you trust with your data
I will use an example here. Elster is a system used by the German government which lets citizens do their taxes online. You can visit it at https://www.elsteronline.de. What most people don't know is that Elster uses JS crypto to authenticate users with a passphrase protected Elster certificate which is decrypted in the browser. Before the crypto trolls start getting hungry, let me explain why this makes perfect sense.
You trust Elster with your tax data and therefor it's ok to trust their web server for authentication. This is not a zero knowledge type application where you're trying to protect your data from a service provider. The user does not want to protect his data from Elster. It is actually Elster that wants to verify that you are the person with the corresponding tax identifier.
The alternative is a Java Applet. Yes, this is how the authentication worked before they switched to the Java-free version. And we all know Java is not famous for it's security track record. So given the choice I'd take JS crypto over having to activate Java in my browser any day.
Services you don't trust (completely) with your data
Now that we've established an example for where a normal web server deployment can make sense, lets look at an example of where it does not make sense. Whiteout Mail is an application designed to make PGP encryption easier for average users (I'm a co-founder and developer). When we started designing the app, we thought about deployment via standard web hosting due to ease of use, but that simply does not make sense for this type of app.
Crypto.cat got a lot of heat by security experts back in the day when it was served via a web server. You can read the two blogposts I linked at the top or just take Bruce Schneier's word for it. This is why crypto.cat changed to an App/Extension based deployment model. This is has several reasons.
You don't trust the web server with your data. If you did you wouldn't be using client side crypto. Every time you click on a link, you're basically "installing" the client side code on your machine to be executed in your browser. The term "drive by web" is usually used here, which basically means that browsers are designed to run arbitrary untrusted code. For zero knowledge type apps, this is not the model we're looking for.
We want auditable static versions. For privacy sensitive applications it is a best practice for software to be installed locally with a static version. This version is signed, downloaded, verified locally by runtimes and can be audited by independent security researchers.
Best practices for JS crypto
It is a bit simplistic to split the world into these two categories, but for starters I hope it will help developers working with the new Web Crypto Apis to understand where to put their application. To help you get started here is a summary of learnings from our work on Whiteout Mail.
For zero-knowledge type applications, use packaged apps. They are available for Firefox, Chrome, and for mobile there's PhoneGap and Google's Chrome mobile apps. Even Microsoft now supports first class HTML5 apps with universal apps for Windows 8.1. The advantage besides security is also that your app can be found in the platform's native app store, which is where most users look to find apps anyway.
For web server deployments use SSL with forward secrecy and activate HSTS (HTTP Strict Transport Security) on your web server. Chrome even supports certificate pinning now.
You should use CSP (Content Security Policy) to protect users against XSS. It's very easy to configure and there is no excuse to not use it. This also forces you to write code with a clean separation of concerns.
Parse data from a server with JSON.parse (never with eval) and escape all strings before inserting them into the DOM. If you're using a framework like Angular.js it will escape models automatically before rendering and it's even compatible with CSP!
Always code in ES5 strict mode. You can use jshint inside your favorite editor (I use sublime) and tools like grunt make it easy to integrate into your test suite.
Write unit tests rigorously. I cannot overstate how important this is. You will not catch regressions otherwise.
Do code reviews before merging changes to the master branch. This will not only catch some security bugs, but also increase code quality and maintainability.
Do regular security audits by independent professionals. They will find stuff. Trust me.
If you can, open source your code. This isn't possible for all business models, but if you can't open source the entire client app, at least open source the crypto bits to allow inspection.
Potential benefits of JS crypto over native crypto
I know I'm stretching a bit here, but bear with me for a moment. Here are a few aspects in which I think JS crypto has an advantage over native crypto: