denoland / deno

A modern runtime for JavaScript and TypeScript.
https://deno.com
MIT License
98.26k stars 5.41k forks source link

Enable non-extractable keys for Web Crypto #11481

Closed lucacasonato closed 3 years ago

lucacasonato commented 3 years ago

Before some we can do this we need confirmation from spec authors for the following statements:

  1. Non extractable keys are not meant to be a security primitive. They are purely meant for obfuscation.
  2. It is expected that a compromise of the render process, or in process timing side channel attacks (Spectre) can extract "non extractable" keys.

If either of these statements are not correct we do not have any technical way to implement non extractable keys securely.

Knowing more about how web crypto is implemented in browsers (Chrome, Safari, and Firefox) would help here:

littledivy commented 3 years ago

The spec recommends use of IndexedDB for storing key material. https://www.w3.org/TR/WebCryptoAPI/#concepts-key-storage


Also:

Authors should be aware that this specification places no normative requirements on implementations as to how the underlying cryptographic key material is stored. The only requirement is that key material is not exposed to script, except through the use of the exportKey and wrapKey operations

I'll assume storing key material in memory is fine with extractable=false

panva commented 3 years ago

The key language from that section I believe is in bold

This allows the storage and retrieval of key material, without ever exposing that key material to the application or the JavaScript environment

That being said that whole section is marked as non-normative.

panva commented 3 years ago

https://www.w3.org/TR/WebCryptoAPI/#scope-out-of-scope

This API, while allowing applications to generate, retrieve, and manipulate keying material, does not specifically address the provisioning of keys in particular types of key storage, such as secure elements or smart cards. This is due to such provisioning operations often being burdened with vendor-specific details that make defining a vendor-agnostic interface an unsuitably unbounded task. Additionally, this API does not deal with or address the discovery of cryptographic modules, as such concepts are dependent upon the underlying user agent and are not concepts that are portable between common operating systems, cryptographic libraries, and implementations.

lucacasonato commented 3 years ago

These sections are all non normative. We can't make a decision on this until we have more clarity about other vendor implementations. Also see https://github.com/w3c/webcrypto/issues/269

panva commented 3 years ago

@lucacasonato can you update the title to state non-extractable rather than extractable?

lucacasonato commented 3 years ago

Ok, this has been unblocked. Discussion here has resulted in the observation that all shipping implementations store key material in an unprivileged process, thus not being "spectre safe". We can thus do the same.

lucacasonato commented 3 years ago

I also reached out to Daniel Huigens (primary editor of the Web Cryptography Specification at the moment). Here is what he had to say:

While I think it would be nice to add protection against Spectre-type attacks eventually, this depends on the feasibility and willingness of implementers to do so, which needs to be investigated, and it would of course be unreasonable to demand that Deno does so while the other implementers haven't yet.

That being said, I do think this is an important issue that deserves more attention, and while the spec in its current form doesn't make any explicit demands from implementers to protect against these attacks, it does leave a lot of freedom to do so, and is intentionally vague about how (and where) cryptographic operations should be implemented and key material should be stored. (And, arguably, Spectre attacks violate the requirement that the private key material is not extractable by a script.) If you are of the opinion that, with Deno's focus on security, it's important to protect against these attacks, then I wouldn't let the lack of an explicit requirement in the spec stop you from doing so. On the other hand, I can also imagine that in a server environment (where I imagine Deno is most commonly used?) where the JS code is "trusted" (modulo supply chain attacks), it may not be worth the effort.

The sort of threat model / scenario that non-extractable keys may be useful for, are things such as:

  1. On first run, an application generates a non-extractable key and stores it in IndexedDB (let's assume the application doesn't have access to disk / to the file where the IndexedDB is stored)
  2. The application sends out the public key and uses the private key to decrypt messages from clients (and stores the messages encrypted in IndexedDB as well)
  3. Then, after some time has passed, one library that the application depends on gets compromised with some code that dumps the entirety of IndexedDB and sends it to some malicious server

If messages are stored encrypted and the private key is non-extractable, then the above attack is prevented. Of course, the attacker could instead decrypt the messages from IndexedDB and then send them over, but that would be a targeted attack and require knowledge of the IndexedDB "schema", etc, whereas the above is a generic attack that would work against any application. With Spectre, the attacker could instead write some code to attack and extract the private key, and it would still be completely application-independent.

In addition, in the case of a signing key rather than a decryption key, extracting the key material allows an attacker to sign new messages for as long as they want, rather than only for the duration of the compromise of the server.

For now we will take the "easy path" where we store key material in process, like existing implementations do. Once (and if) the security model is changed upstream in the spec to be made more strict, we can reconsider.