feat(NODE-7379): Refactor Crypto to Web Crypto API#4862
feat(NODE-7379): Refactor Crypto to Web Crypto API#4862dariakp merged 8 commits intomongodb:mainfrom
Conversation
7ab235b to
4b9a723
Compare
|
Assigned |
There was a problem hiding this comment.
Pull request overview
This PR refactors the MongoDB Node.js driver to use the Web Crypto API (crypto.subtle and crypto.getRandomValues) instead of Node.js's crypto module for most cryptographic operations. This is part of an effort to make the driver runtime-agnostic so it can eventually run in non-Node environments. The only remaining dependency on Node.js crypto is for SCRAM-SHA-1's MD5 digest, which is loaded dynamically via require('crypto').
Changes:
- Replace
crypto.randomByteswithcrypto.getRandomValuesinuuidV4()andrandomBytes(), and replacecrypto.createHash/crypto.createHmac/crypto.pbkdf2Syncwith their Web Crypto API equivalents (crypto.subtle.digest,crypto.subtle.sign,crypto.subtle.deriveBits). - Isolate the remaining Node.js
cryptodependency to SCRAM-SHA-1'spasswordDigestfunction via dynamicrequire('crypto'), and add an eslint restriction on importingcrypto. - Add documentation in README about running in custom runtimes and current limitations.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
src/utils.ts |
Replace crypto.randomBytes with crypto.getRandomValues for uuidV4 and randomBytes |
src/cmap/auth/scram.ts |
Migrate SCRAM auth crypto functions (H, HMAC, HI) to Web Crypto API; isolate MD5 dependency via dynamic require; remove timingSafeEqual |
README.md |
Add documentation section about running in custom/non-Node runtimes |
.eslintrc.json |
Add crypto to restricted imports for test files |
Comments suppressed due to low confidence (1)
src/cmap/auth/scram.ts:355
- Removing
crypto.timingSafeEqualweakens security. The manual XOR loop is not guaranteed to be constant-time in JavaScript — JIT compilers may optimize it in ways that leak timing information, making it potentially vulnerable to timing side-channel attacks on SCRAM authentication. Consider keepingcrypto.timingSafeEqualas the preferred path (via a dynamicrequire('crypto')similar topasswordDigest), with the manual loop as a fallback for non-Node runtimes.
let result = 0;
for (let i = 0; i < lhs.length; i++) {
result |= lhs[i] ^ rhs[i];
}
return result === 0;
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
tadjik1
left a comment
There was a problem hiding this comment.
@PavelSafronov would you mind fixing the documentation typos and clarification that Copilot found? Everything else looks good, thank you! 👍
Co-authored-by: Anna Henningsen <github@addaleax.net>
Description
Summary of Changes
Use standard Web Crypto API
globalThis.cryptoinstead of Node.jscrypto.What is the motivation for this change?
This helps us reduce our runtime dependencies, as part of https://jira.mongodb.org/browse/NODE-6601
Release Highlight
Replaced Node‑specific API
cryptowith standards‑based equivalentThe driver now uses the standard Web Crypto API
globalThis.cryptoinstead of the Node‑specificcryptoAPI.This reduces the number of patches needed to run the driver outside Node.js.
Double check the following
npm run check:lint)type(NODE-xxxx)[!]: descriptionfeat(NODE-1234)!: rewriting everything in coffeescript