Design: Explain security

Created on 19 Jun 2015  ·  26Comments  ·  Source: WebAssembly/design

WebAssembly's security model aims at protecting users from buggy or malicious .wasm files. This doesn't help developers write secure application! Our design should make that distinction clear, explain how WebAssembly implements that security, and what tools WebAssembly expect to be available to help developers create secure applications (this relies on offering the right primitives in WebAssembly).

This is mostly an issue for myself to add this in the design.

All 26 comments

Hi!

I have a question: Would it make sense to elaborate on the following in this context:

"Other than that, programs which invoke undefined behavior at the source language level may be compiled into WebAssembly programs which do anything else, including corrupting the contents of the application heap, calling APIs with arbitrary parameters, hanging, trapping, or consuming arbitrary amounts of resources (within the limits)."
https://github.com/WebAssembly/design/blob/master/CAndC++.md#undefined-and-implementation-defined-behavior

What I'm thinking of is providing context / references which may be (perhaps) of use for the web developers coming from non-native backgrounds -- by providing examples and further discussion.

For instance, CERT's MSC14-C. Do not introduce unnecessary platform dependencies lists four different kinds of Nonportable Behavior (Unspecified Behavior, Undefined Behavior, Locale-specific Behavior, Implementation-defined Behavior) with examples. MSC15-CPP. Do not depend on undefined behavior links to vulnerability C compilers may silently discard some wraparound checks, which may be particularly noteworthy in this context (Robert Seacord discusses this in more detail in "Silent Elimination of Bounds Checks").

More in-depth treatments:

Other potentially relevant advice:

Would having a unique CSP header for controlling wasm files help? I feel like site owners might want to prevent subresources from loading wasm.

That's an interesting question. Definitely we should allow sites to disallow dynamic loading and evaluation of WebAssembly in the same cases they disallow eval and Function (this would just fall out of ES6 module integration and CSP checks on the Loader path). Past that, though, since WebAssembly will be capability-equivalent to JS, I wouldn't think distinguishing the two would be necessary.

It's worth pointing at #53 for a discussion of some of the security concerns with dynamic linking.

@jfbastien yup CORS and SRI should be a available to developers where possible.

@lukewagner I guess it depends on the low level access to resource that wasm will enable. As you say out of the box it is just JS. However it seems the overarching goal of wasm is the closest thing to the machines metal possible; a CSP directive to globally control would be a nice to have.
Over time a more granular approach to the other features would be better too.

The other immediate possibilities are utilising the permissions API for other low level access.

Well, close to the metal in a performance sense. From a security, permissions and sandboxing perspective, there is no discussion of having WebAssembly diverging from JS.

That wasn't the feeling I got from both the post-MVP and Brendan Eichs announcements but ok :+1:

I think what you're referring to is that we've agreed that, post-MVP, WebAssembly semantics would be allowed to diverge from what could be efficiently polyfilled in JS. This divergence would be around computational features, not anything to do with security/permissions. That means that, while they couldn't be polyfilled _efficiently_, new features _could_ be simulated by a WebAssembly interpreter written in JS (Emterpreter-style). It'd probably be good to add a note to this effect to bound what we mean by "diverge from JS".

Yup that would be a good enhancement to the document certainly, I might have read the document too fast but it didn't seem to make that clear.

I think it was one of Eichs talks about adding more threading and memory features that made me think wasm would get new features. I suspect these are likely to be added to JavaScript too and be subject to the usual scrutiny of new features.

"No different from security POV than JS" is now in Web.md.

I'd rather explain the distinction better. Referring to JS isn't very nice from a self-standing perspective, and I think we actually want to reduce the security surface area that JS has (say, cross-origin scripts and such).

I'll get to this, now that I've given a talk about it at CppCon :-)

For those that might be interested in using WebAssembly as a target for cryptographic implementations, elaborating on the differences between the JS/asm.js JIT and the WebAssembly JIT in terms of support for fixed-time implementations would be useful. I'm thinking specifically about operations like bitshifts, post-JIT introduced branches, conditional jumps or lookups, or other changes that the JIT may make that could introduce timing leaks.

If developers should have no expectations of WebAssembly to better support fixed-time implementations than what we already have with asm.js, then stating that would be helpful as part of elaborating on WebAssembly's security implications for application design. If WebAssembly will provide some means of better hardening applications vs. what exists currently (now or after MVP, I haven't read the spec in depth), that would be great to elaborate on too. https://github.com/jedisct1/libsodium.js/issues/24#issuecomment-128002942 has some more on the existing issues around client-side JavaScript crypto.

This is all very exciting, by the way. :D

Agreed that we should have a clarifying statement as suggested by @dconnolly. As of now the discussions we've had were that for MVP there would be no guarantees on what the JIT can / can't do, and that constant-time algorithms aren't the right use of wasm at least for MVP. This may change in the future.

My current take is that external APIs (as offered by the embedder such as the web platform) are better positioned to offer such guarantees because you often need assembly and good understanding of the micro-architecture to write proper constant-time code. Consider the extreme example of a CPU doing dynamic binary translation: WebAssembly can't guarantee what a CPU can / can't do. My view is that WebAssembly is at too high a level of abstraction to express true constant-time code.

Cool, thank you for the clarification. Agreed that web platform APIs are the best place for this sort of thing, especially primitives (WebCrypto is/will be supporting the essentials, with room for future additions like new elliptic curves via notes). Looking forward to that extra language on security, it will help any others who may misinterpret the implications of WebAssembly. :+1:

@jfbastien, does everything you said about wasm timing guarantees still apply today?

I see in the current docs that deterministic execution is a goal except in a small list of documented edge cases, which sounds potentially positive for constant time algorithms. However, webassembly.org/docs/security acknowledges that timing attacks are possible and lists some potential future mitigations, but it isn't clear whether the implication is meant to be that "your buggy C code won't be magically fixed... yet" or "side channel vulnerabilities may be introduced that wouldn't happen with a typical C compiler".

Hard guarantees aside, it would be helpful at least to get a sense of where we stand between "constant time algorithms will 100% definitely get screwed" and "there's no obvious reason not to always expect timing characteristics comparable to clang's native binary output". To @dconnolly's point, some language specifically comparing this with asm.js would also be really useful — particularly taking into account both implementations like Firefox's that fully respect 'use asm' statements and those like Chrome's that play it a bit looser.

@buu700 deterministic result for all opcodes doesn't imply that timing is guaranteed for any opcode. Clang doesn't guarantee constant-time execution either, and constant-time isn't all you need if you're writing infoleak-sensitive code.

Right now, WebAssembly makes no attempt at guaranteeing anything with respect to infoleaks.

Got it, thanks for clarifying the section on determinism @jfbastien.

As far as timing / side channels (and ignoring guarantees or lack thereof), it sounds like there's nothing relevant in the spec about it at this time and no useful data yet about how the actual implementations compare to clang? What I was really getting at, after reading your earlier comment, is whether there's an inherent reason for wasm implementions to necessarily always be _worse_ than gcc/clang in this area. You'd mentioned the level of abstraction as a concern, but it wasn't clear what you were using as a baseline comparison for "good enough" constant timing (native C, assembly, hardware, etc.).

In other words, given the choice between running infoleak-sensitive code on clang and a hypothetical best / most mature / most infoleak-hardened possible implementation of today's WebAssembly spec, would the former still be obviously preferred based on your understanding?

At this point in time, I would rely neither on clang nor WebAssembly for code which is infoleak-sensitive. The only way I currently know to actually get the guarantees I'd desire is by writing assembly which reading the manual for the specific CPU I'm targeting, and with close collaboration from the kernel. Knowing "x86" or "ARM 64" isn't even sufficient if you truly want to be timing independent.

You can get some guarantees with some compilers / languages, but if one infoleak is all that's needed to defeat your code then "some" isn't enough of a guarantee.

Perfect, thanks, I think that answers my question. Agreed on all points about general infoleak threat modeling; I just wanted to get an idea of whether wasm should be considered more leaky than any other (asm-free) C compile target, which it sounds like you're saying isn't necessarily the case?

I don't think "more leaky" is a useful measure. The metric is "does it leak at all?" The answer for WebAssembly, clang, C++, and C, are "yes".

Well, specifically, what I had in mind was algorithms designed to achieve certain side channel resistance properties with pure C implementations, such as the example of libsodium/NaCl linked by @dconnolly. It's certainly ideal if something will survive every possible attack scenario, but it's also useful to know the delta between two things (even if they both suck, by some measure of sucking), and in this case whether using WebAssembly instead of a Linux ABI as a target is likely to break the intended threat model of libsodium.

The linked comment on the libsodium issue thread is very informative on how the library interacts with asm.js, but as a non-expert it's not obvious to me what that specific analysis would sound like rewritten for WebAssembly (aside from i64 support and browsers being more consistent in handling wasm than asm.js).

But anyway, I understand what your original point was from a year ago now, and all I was really concerned about was whether you were making a stronger statement than you actually were (that wasm as a spec was known to introduce specific new side channel weaknesses not found in standard C/clang, as opposed to that neither is generally suitable for that purpose), so thanks for clarifying that.

>

I don't think "more leaky" is a useful measure.

@jfbastien, quantitative security is a field concerned with measuring just
that. The common metric is how many bits of information are revealed by a
successful attack -- 1 bit vs 32 bits, say, makes a huge difference (and in
practice almost every system has small potential leaks through side
channels). Often such quantification is rather difficult, though.

>

I don't think "more leaky" is a useful measure.

@jfbastien, quantitative security is a field concerned with measuring just
that. The common metric is how many bits of information are revealed by a
successful attack -- 1 bit vs 32 bits, say, makes a huge difference (and in
practice almost every system has small potential leaks through side
channels). Often such quantification is rather difficult, though.

I am aware of this, and am thoroughly uninterested because a leak is a leak. If it matters for developers then it'll eventually bite us (the WebAssembly implementors). I don't think WebAssembly should try to tackle this problem any time soon given our other priorities, and that WebCrypto already exists as an effort (despite the shortcoming it may otherwise have, taking this problem on is better than where WebAssembly is at the moment). You can of course explore this at your leisure.

@jfbastien, agreed that this topic doesn't have priority right now, that
Wasm isn't more leaky than C, and that we don't know good ways to tackle
it. But oversimplifications like "a leak is a leak" aren't helpful in that
matter -- every system leaks to some degree, so the quantity is in fact all
that matters. And just waiting til "it bites us" isn't a strategy that's
going to inspire much confidence among the real potential victims, namely
browser users.

agreed that ... Wasm isn't more leaky than C

Nice, thanks for explicitly confirming that! That's all I came here for: a general sense of what I should compare it to, not a guarantee of whether it "won't leak".

@rossberg-chromium I don't think I'd agree with the idea that wasm isn't more leaky than C. In the end that depends on how each engine implements everything. For example, JavaScriptCore tiers up code and stops tiering up code when it runs out of executable memory. This is a leak that does not exist with C code. I would expect, as wasm engines get more advanced, wasm will be likely as leaky as something like the JVM. Ultimately, I don't the spec or implementors are likely to strive to accommodate preventing information leaks, especially not at the cost of performance.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

KloudKoder picture KloudKoder  ·  55Comments

ngzhian picture ngzhian  ·  41Comments

sebmarkbage picture sebmarkbage  ·  41Comments

PoignardAzur picture PoignardAzur  ·  61Comments

autumnontape picture autumnontape  ·  38Comments