Before getting down to today’s topic, Web Cryptography API, note that all the photos below are available here1https://github.com/ExcelliumSA/WebCryptographyAPI-Study/tree/main/post in better quality.
The library has been working well for years, so why should I stop using it?
No troll allowed here
The goal of this blog post is not to say that Web Cryptography API is the best API or that you must replace your existing JS cryptographic API with Web Cryptography API.
The goal is just to present to you what Web Cryptography API is and what it offers.
What is the Web Cryptography API?
To summarize, it brings native capabilities to browsers to perform different types of cryptographic operations using an API:
- Generate cryptographically random values.
- Encrypt and decrypt content using symmetric or asymmetric encryption algorithms.
- Sign and verify the signature using symmetric or asymmetric algorithms.
- Derive key and bits from base keys or source of bits.
- Generate hash of content.
In addition, it supports operations regarding the key management :
- Generate symmetric or asymmetric keys for different kinds of usage.
- Export/import key using secure/insecure methods.
The API does not handle the following aspects43. https://w3c.github.io/webcrypto/#scope-out-of-scope (some points in the list below were directly taken from the RFC):
- Key (secure) persistence in browser storage systems.
- The provisioning of keys in particular types of key storage, such as secure elements or smart cards.
- Communication and discovery of cryptographic modules.
- The RFC places no normative requirement on how implementations handle key material once all object references to it are removed.
Why Web Cryptography API is not the Holy Grail?
The API provides low-level cryptographic operations, so, it requires to know “what you are doing” when using the different features. Indeed, the API does not protect you against incorrect usage55. https://cwe.mitre.org/data/definitions/329.html of the cryptographic algorithms supported.
In addition, like crypto-js, the API supports deprecated algorithms like MD5, SHA1, ECB mode of operation of AES, CBC mode of operation of AES, etc, thus, no warning will be raised if you decide to use one of them whatever your usage is legit or not.
In the same way, the Web Cryptography API will not warn you or raise an error if you create/use a key with broader key usages than the real one needed for the cryptographic operations performed.
Why should I consider the Web Cryptography API?
Cryptography is a very complex and error-prone domain. Even if you stick to the standard, you can create a vulnerable code. Besides incorrect usage of a cryptographic library, one of the pitfalls is the quality of the implementation of the supported algorithms. Indeed, this type of issue is “invisible” for most of the users of a cryptographic library (including for the author of this blog post) in the way that it requires specific skills to identify that, the implementation of a cryptographic algorithm is unsafe.
For example, how you ensure, in an accurate way, that the cryptography library that you are using:
- Implement correctly the algorithm that you want to use.
- Provide battle tested implementation.
- Patch, in an effective way, any security weakness identified.
- Maintain, over time, the different implementations of the algorithms supported.
- Is implemented by people having the required skills/experience.
Here comes the Web Cryptography API, by using it, you delegate the validations above to the provider of the browser, i.e. Google (Chrome), Mozilla (Firefox), Microsoft (Edge), Apple (Safari) for the main browsers. The section of the RFC named “Underlying Cryptographic Implementation” 66. https://w3c.github.io/webcrypto/#concepts-underlying-implementation defines the following statement:
“This specification assumes, but does not require, that conforming user agents do not and will not be directly implementing cryptographic operations within the user agent itself. Historically, many user agents have deferred cryptographic operations, such as those used within TLS, to existing APIs that are available as part of the underlying operating system or to third-party modules that are managed independently of the user agent.”
The RFC recommended to browser providers not to implement cryptographic functions themselves but instead leverage industry-recognized modules. It is true that here we are in “delegationception” because you trust the browser that delegates the handling of cryptographic operations to another third party.
In addition, using Web Cryptography API brings the following benefits:
- Make “supply chain attack” harder against your application7https://docs.microsoft.com/en-us/windows/security/threat-protection/intelligence/supply-chain-malware.
- Bring better performance for cryptographic processing.
The end of white rabbit syndrome87. https://en.wikipedia.org/wiki/White_Rabbit
From a patching point of view, if a critical issue is identified in the implementation of an algorithm, you will not need any more to identify, in urgency, which of your web apps are using the vulnerable versions of the cryptographic library and then perform multiple updates and redeployments. The patching will be ensured via the auto-update feature of each browser. Most of them now have such a feature to keep them up to date.
To be honest a second, let us agree that entity like Google/Mozilla/Microsoft/Apple are better at cryptography/patch management than your company (mine included). Therefore, even if we are in two-stages delegation as described in the previous section, security level will be better than if you need to patch all your applications yourselves.
Browser support level
Web Cryptography API capabilities
This section provides an overview of the capabilities brought, currently, by the Web Cryptography API (June 2021).
The source was the Mozilla documentation108. https://developer.mozilla.org/en-US/docs/Web/API/Web_Crypto_API combined with the RFC119. https://w3c.github.io/webcrypto/#algorithm-overview as well as validation using the labs presented (see further1210. https://github.com/ExcelliumSA/WebCryptographyAPI-Study).
Algorithms and operations supported:
|Cryptographic operation||Supported algorithm||Protocol*|
|Generate cryptographically random values||–||HTTP
|Generation of a symmetric key for encryption/decryption||AES-CBC
|Generation of a secret for symmetric signature/validation||HMAC|
|Generation of an asymmetric key pair for encryption/decryption||RSA-OAEP|
|Generation of an asymmetric key pair for signature/validation||RSASSA-PKCS1-v1_5
|Symmetric signature and validation||HMAC|
|Asymmetric signature and validation||RSASSA-PKCS1-v1_5
|Key derivation / bit derivation||ECDH
|Key wrapping – From Mozilla documentation:
“Exports the key in an external, portable format, and then encrypts the exported key.
* If you are using an insecure protocol for operation requiring HTTPS (named secure context), the following error will be raised (the subtle attribute member of the crypto object is not defined):
Key export format:
- Raw: Array buffer containing the raw bytes for the key.
- PKCS #81311. https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/importKey#pkcs_8 .
- SubjectPublicKeyInfo1412. https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/importKey#subjectpublickeyinfo
- JSON Web Key1513. https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/importKey#json_web_key .
Avoid hidden trouble with the API
Below is a set of key points to avoid traps of the Web Cryptography API:
- Do not use deprecated algorithms / Ensure to correctly use an algorithm1614. https://www.keylength.com/en/3/ 1715. https://bettercrypto.org/#theory:
- If you have any doubt about an algorithm or its correct usage then ask to a friend or colleague with skills in the cryptographic field.
- Doubting and asking questions is a healthy attitude when it comes to choosing or correctly using a cryptographic algorithm as well as most things in life.
- Do not use the function getRandomValues() to generate a key, use the dedicated generateKey()
- During the generation of a key, only set key usage consistently for the usage of the key via the parameter named keyUsages of the generateKey() function1816. https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/generateKey#parameters .
- If the key you generated is not intended to be exported, for example, because it will be only used for a temporary operation then mark it as non-extractable via the parameter named Extractable of the generateKey(). In case of doubt set this parameter to false.
- Affecting the value false to the parameter extractable indicates that the key cannot be exported.
- To export a key always use the wrapKey() function except if you know exactly what you are doing using the exportKey() function.
Why should I not consider the browser storage systems as secure?
A common and quick reflex can be to use the exportKey() function and store the exported content of the key in the IndexedDB browser storage systems like suggested by the RFC in section named “Key Storage”.2121. https://w3c.github.io/webcrypto/#concepts-key-storage
A question comes to mind; does the browser protect the content stored in the IndexedDB storage when data is at rest?
1. Store an exported key2222. https://github.com/ExcelliumSA/WebCryptographyAPI-Study/blob/main/docs/js/commons.js#L179 in an IndexedDB using Firefox:
2. Check the file system level, if it is possible to access the content of the key by reading the SQLite database used to store IndexedDB data:
We can access the stored content. 🙁
We can access the stored content too 🙁.
Same test for Edge (Edge also uses the LevelDB format):
Same result 🙁.
In conclusion, consider the browser storage systems as unsafe from a file system point of view. Indeed, as demonstrated above, if the insecure function exportKey() is used to export the key and the value is stored in the browser storage systems, then, the browser does not provide itself with a layer of protection against direct access to the exported key value via the browser system files.
Built-in protection against local Denial of Service
Browsers implement protection preventing usage of cryptographic functions in a way that can cause instability or browser crashes. Below are some examples of limitations that are implemented.
Here is an example of a limitation implemented in the function getRandomValues() – The request length cannot be superior to 65536 bytes:
Another example of limitation implemented. Here, in the encrypt() function when used with an asymmetric key pair. In this example, the input data to encrypt is too large:
However, for the example above, depending on the way in which the cryptographic function is called, it may bypass the protection above and trigger another one or not…
When this test2424. https://github.com/ExcelliumSA/WebCryptographyAPI-Study/blob/main/docs/js/operations.js#L140 is called, then, it triggers the sandbox protection on Chrome and Edge, at no moment the browser becomes unstable:
On Firefox, the browser becomes unstable and must be killed using the task manager. See this video2525. https://github.com/ExcelliumSA/WebCryptographyAPI-Study/blob/main/demo-instability.mp4 for a complete demonstration of the behaviour.
It is not always required to make a choice…
It can be tempting to replace any crypto library currently in a project with the Web Cryptography API. The author thinks that is not a recommended way due to the following reason discovered during its study: The Web Cryptography API provides low-level cryptographic features, so, its usage requires skills in the crypto domain to not bring vulnerability via a bad usage of any features/algorithms.
Most of the popular cryptographic libraries, like crypto-js, provide high-level cryptographic features in order to make the important decision, regarding good usage of crypto primitives, behind the scenes for the user and prevent him to misuse for example AES algorithm, pseudo-random number generator, etc.
In addition, popular cryptographic libraries, like crypto-js, has already started using Web Cryptography API under the hood when it is available:
The following PowerShell script2626. https://github.com/ExcelliumSA/WebCryptographyAPI-Study/blob/main/stats.ps1 takes the first-page result of a search for “crypto” packages against the NPM registry and try to find any reference to the Web Cryptography API in the code base of the source Git repository:
Execution of the script gave the following results:
Therefore, no need to leave your favourite cryptographic library if it supports Web Cryptography API when it is available. 😊
In order to experiment with all elements mentioned in this post, a lab was created2717. https://excelliumsa.github.io/WebCryptographyAPI-Study/.
The lab has the following user interface and provides a playground to discover/explore/test the different features provided by the Web Cryptography API:
The lab features were tested on the last version (in June 2021) of Chrome, Firefox and Edge. All features were fully documented to allow easy access.
All cryptographic operations were centralized in a JS script named “operations.js” to facilitate the reading/understanding of the code as well as the modification to explore custom test cases2818. https://github.com/ExcelliumSA/WebCryptographyAPI-Study/blob/main/docs/js/operations.js .
All study notes gathered were provided2919. https://github.com/ExcelliumSA/WebCryptographyAPI-Study/blob/main/study-note.pdf to provide all information/hypotheses/assumptions that were used/made to create this blog post.
This post explored the new capabilities as well as the pitfalls brought by the Web Cryptography API.
The study provided the following courses:
- It provides low-level crypto features, therefore, it requires skills in the crypto domain to use them wisely without introducing vulnerabilities.
- It provides a common layer of crypto capabilities, at browser levels, allowing existing cryptographic libraries to leverage it in order to provide a collection of high-level and safe crypto features usable by developers. Safe in the way in which, high-level crypto features make the important decisions, regarding good usage of crypto primitives, behind the scenes for the developer to prevent him/her to misuse
- Some part of the RFC remains imprecise, causing a browser provider to make its own path in some areas like for example the selection of the third-party cryptographic components handling cryptographic operations, or the support of key management systems. This can lead to vulnerabilities and technical incompatibilities in some browsers based on these decisions.
As a takeaway, the authors will keep this decision tree in mind:
Did you like this article? Find great other articles in our blog section.