From : Tom Ritter < : Tom Ritter < tom@ritter.vg



Message-ID : <CA+cU71=ZT66LpY__=OHJi9d2FOKg++V-pKP1E2vrAP+8YyGhNA@mail.gmail.com>

To : public-identity@w3.org



So after my use cases I hit up against the problem of verifying a javascript runtime. The end goal is making javascript secure for crypto operations, so let's look at that problem and then wittle it down to the runtime problem. Right now, javascript crypto is no good for a number of reasons: - Third-Party Problem: Any third party supplying code can poison the entire runtime - XSS Problem: Any XSS flaw can poison the entire runtime - MITM Problem: Without SSL, the code can be modified easily by a middler - SSL Problem: SSL Authentication (CAs) blows - Modified Problem: Even if you validate an entire runtime today, you have to do it again tomorrow to make sure it didn't change - RNG Problem: Javascript doesn't have a secure RNG - Implementation Problem: You shouldn't write your own crypto. - Keystore Problem: Where do you keep your keys? - Side Channel Problem: Timing attacks - Coercible Problem: Basically, the modified problem, but adapted to the site operator being forced to trojan you. http://www.matasano.com/articles/javascript-cryptography/ is a good article on the topic Let's start out by knocking off MITM and SSL: let's use SSL with Key Pinning so you can trust the SSL connection. Next let's kill the RNG and Implementation problems: DOMCrypt is the proof-of-concept of a subset of what we want to built: native methods exposed via javascript that have a good RNG and good crypto implementations. And, let's knock off the Keystore for this thread so we can focus on the runtime. And finally, to keep things simple for now I'm going to ignore Side Channels. Let's focus on what's left: - Third-Party Problem: Any third party supplying code can poison the entire runtime - XSS Problem: Any XSS flaw can poison the entire runtime - Modified Problem: Even if you validate an entire runtime today, you have to do it again tomorrow to make sure it didn't change - Coercible Problem: Basically, the modified problem, but adapted to the site operator being forced to trojan you. How would you change HTML, Javascript, the DOM, and browsers to solve these problems, so a simply-stated-but-complicated example like "PGP in gmail" is actually secure? You can make any changes you want but the more complicated it is the less implementable it is, and that's points subtracted. And anything that requires a user to make a trust decision is also points off, because users always make the wrong trust decision and don't change defaults. Here's my idea. There's a lot of hand-waving in it, and several things that probably just wouldn't work well, but I think the ways it's broken can help illuminate the problem of the javascript runtime of a page being too malleable for crypto operations as it exists now. So something in that runtime has to change. First we knock out the 3rd Party and Modified problems by code-reviewing and signing javascript libraries. Imagine if BouncyCastle wrote an OpenPGP javascript library that called the native crypto methods and just handled that annoying OpenPGP stuff for you. You trust BouncyCastle to write good, correct code - but you don't trust a CDN to serve it unmodified. <script type="text/javascript" src="https://cdn.google.com/libraries/bouncycastle-openpgp-1.3.4.js" signature="SADfskdjahflkjh32q239oyhfd89awydflihq3e3o92==" /> That signature attribute is the hash of the library, signed with the private key of the SSL connection. If that file changes, the signature doesn't validate, and the file contents are never executed. File can't be modified without invalidating the signature or finding a collision in SHA256 (or whatever). You sign the javascript files once, and hardcode signatures - you don't need or want to do online signing. But you've still got the huge problem of the entire javascript runtime (which includes this signed third party library) can be poisoned by a stray XSS flaw. My idea is two execution environments: "Crypto" and "Everything Else". [1] <script type="text/javascript" src="https://cdn.google.com/libraries/bouncycastle-openpgp-1.3.4.js" signature="SADfskdjahflkjh32q239oyhfd89awydflihq3e3o92==" runtime="crypto" /> <textarea id="email" runtime="crypto">Type your message here</textarea> Javascript code in the crypto runtime can see the DOM, hook it and interact with it just like javascript today. And so can the everything-else runtime. But variables and functions from one runtime cannot interact with the other. What's more - if a HTML element specifies a runtime, it's 'private data' (that's a little hand wavy but for now just say it's contents) is not accessible to any other, nor can it be hooked by any other runtime. So the email textarea above could only be read (.innerHTML) or hooked (onkeydown) by the crypto runtime. The bare minimum of javascript code is in the crypto runtime - no UI stuff, no user input. An XSS flaw in it would bring the security model crashing down, yes. But if the crypto-runtime javascript code is small (say 5% of all js code) and carefully written - your risk is minimized. It's no different from SetUID or privilege-dropping daemons - you're extra careful about code you write that runs as root. A normal XSS flaw wouldn't be able to rewrite crypto functions, see their state, read the contents of sensitive HTML elements, or hook them. Pros: - No changes to javascript language - Minimum changes to HTML spec - [1] You can have N execution environments, I just simplified it Cons: - Big performance problems for javascript/DOM access - Side Channels - Lots of corner cases about what access can and can't be allowed Now the Coercible Problem. You want to be a good netizen and only serve trustworthy code, but you have the misfortune to operate in a country where the government coerces you with guns or national security letters. This one's tricky, but basically something in the browser that watches signed javascript libraries, and alerts you to changes. That's UI stuff that's out of scope, I just included it for completeness. I think the javascript runtime environment is a very tough problem to solve for javascript crypto to be feasible. There's probably going to need to be some huge specification document about how just the runtime will act. This was a 'first-thought' idea - the places where it fails should help illustrate what the requirements for that spec doc would be. By all means, point out its specific flaws in addition to discussing the 'runtime problem', but please also include the sentence "A proper implementation would X". -tom