W3C home > Mailing lists > Public > public-webcrypto@w3.org > March 2013

Re: On Crypto API Safety in the Hands of Unskilled Developers

From: Richard Barnes <rbarnes@bbn.com>
Date: Thu, 28 Mar 2013 16:59:44 -0400
Cc: Mark Watson <watsonm@netflix.com>, public-webcrypto@w3.org
Message-Id: <8E135E00-6668-4445-A383-6726FD57BC5C@bbn.com>
To: Ryan Sleevi <sleevi@google.com>
Ryan,

The high-level / low-level distinction you're drawing here is specious.  What this group produces is *the* API.  It's impossible for us to limit it to some particular class of developers, so we need an API that can provide scalable complexity.

The utility of XMLHttpRequest for XSS / CSRF is actually a nice example of this sort of scalability.  XHR is subject to the same-origin policy, because that's a safe default.  But you can use CORS to implement more advanced use cases.  General HTML document assembly is the opposite example, where the starting point was too open, and now we need CSP to lock it back down.   

What I'm arguing is that we should follow the XHR example instead of the HTML example.  Make the easy case safe, but allow for the complex stuff.  Don't force developers to risky stuff they don't want to do, just to make something basic.

I'm also not suggesting huge changes here:
-- Allow for the algorithm parameter (or parts of it, like IVs) to be optional in encrypt/sign
-- Add a toString() method (or something similar) to CryptoOperation

I've asked before for examples of how these are harmful.  Maybe I'm forgetting some, but the worst case I remember you bringing up is that default parameters could lock browsers into a choice.  As I explained in the essay below, that is a problem, but it's one that can be addressed by also making it easy for developers to capture all the data they need.  What's the remaining risk?

By way of contrast, here's my 3-line horror story for the current API:
    let alg = { name: "AES-GCM", params: { iv: new Uint32Array([0,0,0]), tagLength: 0 }}
    let op1 = window.polycrypt.encrypt( alg, key, content1 );
    let op2 = window.polycrypt.encrypt( alg, key, content2 );
Run that by some developers, see if they can spot the problem.  

Contrast with proposed syntax:
    let op1 = window.polycrypt.encrypt( "AES-GCM", key, content1 );
    let op2 = window.polycrypt.encrypt( "AES-GCM", key, content2 );
UA provides a fresh IV and a full-length authentication tag, nobody gets hurt.  But if you want to specify those things, you still can!  

--Richard





On Mar 28, 2013, at 11:52 AM, Ryan Sleevi <sleevi@google.com> wrote:

> Mark,
> 
> Richard's points about defaults gave been repeatedly discussed in the group and numerous examples provided for how they fundamentally represent bad API design for a low-level API, but are very much a part of a high-level API.
> 
> Further, it has also been discussed with how the argument that crypto is somehow "special" or inherently more dangerous than other APIs is a fundamentally flawed assertion. The ability for CSRF, cookie leaking, or XSS all represent vastly more serious and real threats than bad cryptography.
> 
> Developers can write extremely poor performant WebGL, but you don't see us discussing VRML as the solution. Developers can write absolutely horribly performing CSS, but you don't see us discussing ways to provide a default set of "site templates," ala GeoCities of yore, to have code blessed by the design priesthood.
> 
> The argument that Crypto can or is used to implement "security," a fundamentally amorphous term that van mean completely contradictory things depending on personal views (e.g. DRM) is irrelevant to the discussion of the API - but it makes up the fundamental argument of Richard's position.
> 
> There is unfortunately nothing here that has not already been discussed at length, and with numerous examea provided as to its unsuitablity for a low-level API.
> 
> Discussions of parameters and serialization are EXACTLY the issue that a high-level API tries to solve; when you say 'let's combine primitives and serialization/persistence', you are no longer discussing a low-level API.
> 
> I did not say Richard's points were wrong - in the context of a high-level API, they're an imminently sensible reminder of objectives. But in the context of a low-level API, but especially in the context of this group, its a retread of points not applicable.
> 
> On Mar 28, 2013 8:42 AM, "Mark Watson" <watsonm@netflix.com> wrote:
> Ryan,
> 
> I thought Richard's piece was well written, made some good points and was clearly targeted at the low-level API on which we are working. His suggested remediation for the problems is straightforward. IMHO, at the very least, it deserves a more considered response.
> 
> ...Mark
> 
> On Thu, Mar 28, 2013 at 8:39 AM, Ryan Sleevi <sleevi@google.com> wrote:
> Thank you for your description of a high-level API.
> 
> At this time, the WG is pursuing a low-level API.
> 
> On Mar 28, 2013 8:21 AM, "Richard Barnes" <rbarnes@bbn.com> wrote:
> The SubtleCrypto thread reminded me that I'd been meaning to send out some notes I wrote down about unskilled developers.
> 
> Brief essay follows.  Comments welcome.
> 
> --Richard
> 
> 
> 
> On Crypto API Safety in the Hands of Unskilled Developers
> =========================================================
> 
> I. What is the problem (general)?
> ---------------------------------
> 
> The current API's approach of exposing unmitigated complexity to the developer -- no defaults, no help from the browser -- is only plausible if we assume that the only people who will use the API are experienced cryptographers.  This assumption is clearly not true.  Any API that is supplied in the DOM will be exposed to, and get used by, a much wider variety of developers than we ever intend.
> 
> That's true of any DOM API, whether it's crypto, geolocation, canvas, etc.  But crypto is special.
> 
> -- Bad crypto design leads to worse consequences
> -- Bad crypto design is hard to detect
> 
> The whole point of having a crypto API is to protect sensitive things.  So by definition, if you screw up your usage of the crypto API, you are exposing sensitive things.  Moreover, if this happens, you are likely not to notice it.  If you screw up your WebGL rendering code, things will look bad.  If you re-use the same nonce twice in GCM, nothing is obviously different.
> 
> So in its current state, the API makes it likely for bad things to happen.  It would be irresponsible of this group to release an API in this state.  We need to think seriously about how to make the default mode of the API less likely to lead to pain, while still allowing for full generality.
> 
> Think of this like consumer protection.  You can't ship a lawn mower that doesn't have a guard around the blade.  Someone can buy a lawn mower, take off the guard, and use the motor and blade in new and creative ways, at the risk of injuring himself.  Even if someone isn't doing something advanced, they can still stick their hand under the guard and get cut.  But by default, in most use cases, the lawn mower is safe to use.
> 
> 
> 
> II. What is the problem (specific)?
> -----------------------------------
> 
> Conceptually, there are two classes of CryptoOperation: "Plain to ciphertext" operations that convert plaintext to data with cryptographic structure, and "Cipher to plaintext" operations that do the reverse.
> 
> P2C       C2P
> -----------------
> sign      verify
> encrypt   decrypt
> digest
> 
> The difference is this: P2C operations can meaningfully be done with many different choices of parameters.  C2P operations can only be done with a specific set of parameters.
> 
> Both of these create problems for developers.
> 
> For P2C operations, the developer must choose how to set multiple parameters, choices that are likely not obvious to someone not skilled in the art.
> For C2P operations, the developer needs to make sure that they keep all the relevant parameters together with protected information.
> 
> So we have two problems:
> P2C: How to help developers make good choices
> C2P: How to help developers keep ciphertext associated to parameters
> 
> 
> 
> III. What would a solution look like?
> -------------------------------------
> 
> On the face of it, the P2C problem -- choosing parameters -- seems easy to solve.  If there are multiple valid sets of parameters, just have the browser / API implementation make the choice on behalf of the developer.
> 
> However, this exacerbates the C2P problem, because there are now many ways for the ciphertext to be separated from its parameters.  If a web app does not store the parameters with which the ciphertext was computed (relying on the browser's defaults), then if the browser changes defaults, then the app will be unable to decrypt the ciphertext (or validate the signature).  Even if the app stores the parameters, then it needs to make sure that the ciphertext is always associated with the correct parameters; the app cannot, for example, send the ciphertext for storage on a server, but not the parameters.
> 
> So in order to solve the P2C problem, we also need to solve the C2P problem.  Namely, we need to make it easy by default for apps to keep parameters and ciphertext together.  In API terms, that would seem to indicate that the results of a crypto operation should be provided as an object that contains all the relevant parameters (as indeed, CryptoOperation already does).  In addition, it would be helpful if this object had a default serialization, to address the issue of parameters getting lost when the object is stored or sent someplace else.
> 
> This gives us two solutions to match the two problems:
> P2C: Provide browser-chosen defaults
> C2P: Provide results in an object with parameters and a serialization
> 
> These don't prevent developers from running into problems -- choosing bad IVs, or deleting default parameters from the object -- but it encourages a default life-cycle that should be problem free:
> * Process plaintext, get ciphertext+parameters
> * Store ciphertext+parameters
> * Process ciphertext+parameters, get plaintext
> 
> These solutions also donít get in the way of more advanced developers.  You can still specify all the parameters, and still use whatever parts of the object you want.
> 
> 
> 
> 
> 
> 
> 
> 
Received on Thursday, 28 March 2013 21:00:15 UTC

This archive was generated by hypermail 2.3.1 : Tuesday, 6 January 2015 21:17:16 UTC