2016-07-14

The Browser is the Worst Sandbox Ever Designed

I want to convince you, dear reader, that we’re building browsers wrong. And sandboxes, for that matter.

For a long time I had a low opinion of Rust and a high opinion of Servo. My rationale was that it’s wasteful to obsolete tens or hundreds of thousands of experienced C and C++ programmers and try to retrain them in a new language. However, I thought, Rust really was the only possible approach to building a secure web browser, and Servo would be everything a browser should be and more.

I still think Servo has some great technologies, particularly WebRender, which is the way browsers should’ve rendered pages since the beginning. It will be a huge revolution.

But aside from all the cool Servo features, I’ve reversed my opinion nearly 180 degrees. Rust will be great for certain applications (in particular, not applications), and on the other hand, Servo won’t be more than 2-10 times more secure than existing engines (Blink, WebKit or Gecko), which isn’t enough.

The core argument is this: security risk is the product of defect rate multiplied by attack surface. Blink raised the implementation quality bar with it’s tab-per-process design and privilege dropping. Servo will doubtlessly raise it again with Rust and very careful coding. However, this is fundamentally a losing battle. The attack surface of every existing browser (including Servo) is every feature and API they provide. Every new web standard, which might be drafted or implemented by interns (no offense), risks the security of the entire browser, whether anyone uses it or not.

I think it’s reasonable to say that half of all security bugs are due to memory safety. Maybe it’s worse in browsers. Charitably, let’s say Rust prevents 90% of bugs in equivalent C++ code. Chrome has too many security bugs, despite all of the precautions and mitigations it already takes, and rewriting a browser engine from scratch is too herculean (the Servo nightlies are still mostly a curiosity at this point) for this approach to make sense. Even if Servo succeeds in its goals, Rewrite it in Rust is not enough bang for too much buck.

Is there an alternative? Yes. This problem is a classic combinatorial explosion, because attack surface and features are directly coupled. The classic solution to every combinatorial explosion is modularity: separation of concerns.

The Strongest Security is only Skin Deep

We need a highly secure (ideally provably secure) sandbox that doesn’t have any features! Then, you can run an insecure browser inside, where security doesn’t matter.

I’ve been looking for relatively secure sandboxes that could run existing web browsers with minimal work. The pickings are slim. If you want something today, the best option is probably Xen, perhaps in the form of Qubes OS (of which I am a huge fan).

In the slightly longer term, I think the most promising option is a lighter weight sandbox that doesn’t require taking over your whole operating system (since that won’t fly for most folks, although Qubes has a lot of additional benefits). The closest we’ve got is something like Google’s Native Client.

Basic steps:

Recompile a browser like Chromium or even NetSurf for NaCl. There is no step 2!

Okay, that’s not quite feasible yet.

(What about portability? Do it inside the sandbox. JIT compilers are yet another complex set of constantly-evolving features, which is why I now think NaCl is more important than PNaCl or WebAssembly.)

What Features does a Secure Sandbox Need?

You may have noticed that Xen has a lot of security bugs too. My argument is that even Xen has too many features. It keeps changing.

The features of a general-purpose, secure sandbox aren’t actually defined by the applications that it runs. Instead, they’re defined by the hardware it runs on. Basically, you need to provide some sort of isolated path to each underlying feature the hardware provides. For example, you need a secure drawing API (including 3D, which, yes, is hard). You need a secure file system. You need secure network, and microphone, and webcam, and probably even USB. (It should also be possible to block or control access to each of these.)

This is hard enough, without even worrying about web-specific features like parsing HTML, CSS, JavaScript, and providing APIs like IndexedDB or WebSQL. It still requires a lot of parsing, which is always risky. Incidentally, that is what Rust is good for.

Rust is a Language for Writing Secure Sandboxes

This sandbox has to be very fast and lightweight. And secure, obviously. As much as I like C, I’m happy to admit that no language can compete with Rust here. After all, it’s what Rust was designed for!

Now, let’s stop writing secure applications. We need a single, bulletproof sandbox, a few bulletproof libraries and multi-user systems (where simple sandboxing tends to fall down), and a wide variety of apps written without a thought to security concerns (like how most apps are written today, especially games).

Modularity! Separation of concerns! Spray-on security! Sandboxing!

Thanks for your time.