Node.js Crypto 模块全攻略:从哈希到非对称加密

·

关键词:Node.js Crypto、哈希算法(MD5/SHA1/Bcrypt)、Hmac、AES、RSA、Diffie-Hellman 密钥交换、JavaScript 加密

为什么用 Node.js 做加密?

浏览器端可以用 WebCrypto API,但在服务端处理 数据完整性校验密码存储 或者 Token 加密 时,Node.js 自带的 node:crypto 模块仍然是最高效、最灵活的选择。它底层用 C/C++ 实现,暴露了简洁的 JavaScript 接口,既不会拖慢服务器性能,又能让你用几行代码完成复杂的安全逻辑。


1. 哈希算法:MD5 / SHA 家族

哈希算法会“压扁”任意长度的输入,输出固定长度的 十六进制摘要。只要 1 bit 有变,整个结果面目全非。

import crypto from 'node:crypto';

const hash = crypto.createHash('sha256') // 或 'md5'、'sha512'
                  .update('Hello, Node.js!')
                  .digest('hex');
console.log(hash); // e868...

常见场景

进阶提示
MD5 已被彩虹表击穿,生产环境建议使用 bcryptArgon2。如果仅限于校验文件完整性,sha256 是目前最通用且运行速度适中的选择。

2. Hmac:给哈希加一把钥匙

JWT Token支付回调签名校验 等场景里,只靠哈希是不够的;还要用一把只有前后端知道的密钥(Secret)重新算一次摘要,这就是 Hmac

const hmac = crypto
  .createHmac('sha256', process.env.API_SECRET) // Secret 建议 32+ 字节,不硬编码
  .update('orderId=123&amount=100')
  .digest('hex');

只要密钥变了,同一消息也得出相反的结果,解决 数据伪造 问题。


3. AES 对称加密:加解密同钥

HTTPS 使用的 SSL 不同,AES 是对称算法,加密、解密共用一个 key + IV

import crypto from 'node:crypto';

function aesEncrypt(key, iv, msg) {
  const cipher = crypto.createCipheriv('aes-256-cbc', key, iv);
  return cipher.update(msg, 'utf8', 'hex') + cipher.final('hex');
}

function aesDecrypt(key, iv, encrypted) {
  const decipher = crypto.createDecipheriv('aes-256-cbc', key, iv);
  return decipher.update(encrypted, 'hex', 'utf8') + decipher.final('utf8');
}

const key = Buffer.alloc(32, 'Passw0rd'); // 32 字节
const iv  = Buffer.alloc(16, 'Node.jsIV'); // 16 字节
const msg = 'Keep it secret, keep it safe';
const encrypted = aesEncrypt(key, iv, msg);
console.log(encrypted); // 7828...

👉 30 分钟手写快速上手加密实战,不看代码也能懂

关键踩坑


4. 非对称加密:Diffie-Hellman 密钥交换

作为 密钥协商(Key Agreement) 而非消息加密的方案,DH 可以让双方在不泄露私钥的情况下,算出共享的秘密 对称密钥

import crypto from 'node:crypto';

// 甲方
const alice = crypto.createDiffieHellman(512);
const alicePublicKey = alice.generateKeys();
const prime = alice.getPrime();
const generator = alice.getGenerator();

// 乙方
const bob = crypto.createDiffieHellman(prime, generator);
const bobPublicKey = bob.generateKeys();

// 双方各自计算共享密钥
const aliceSecret = alice.computeSecret(bobPublicKey);
const bobSecret   = bob.computeSecret(alicePublicKey);
console.log(aliceSecret.equals(bobSecret)); // true

用这段共享密钥可直接做 AES 加解密,实现 双向安全信道


5. RSA:非对称加解密的瑞士军刀

RSA 一对密钥(公钥可公开,私钥必须保密)广泛用于:

5.1 生成密钥对

# 生成 2048 位私钥,用 AES256 套外壳
openssl genrsa -aes256 -out rsa-key.pem 2048
# 提取原始私钥
openssl rsa -in rsa-key.pem -out rsa-prv.pem
# 导出公钥
openssl rsa -in rsa-key.pem -pubout -out rsa-pub.pem

5.2 实战:公钥加密、私钥解密

import fs from 'node:fs';
import crypto from 'node:crypto';

const pubPem = fs.readFileSync('./rsa-pub.pem', 'utf8');
const prvPem = fs.readFileSync('./rsa-prv.pem', 'utf8');

const msg = 'Top Secret';
const encrypted = crypto.publicEncrypt(pubPem, Buffer.from(msg));
const decrypted = crypto.privateDecrypt(prvPem, encrypted);
console.log(decrypted.toString()); // Top Secret

注意
RSA 块大小上限 = 密钥长度/8 - 11 字节,2048 位最多能加密 245 字节数据。常见套路是:

  1. 服务器随机生成 AES Key
  2. 用 RSA 公钥把 AES Key 加密
  3. 用 AES Key 把大量数据加密
  4. 客户端拿到两部分——AES 密文 + RSA 加密后的 Key,顺序相反即可还原。

FAQ:Node.js Crypto 最常用的六个疑问

Q1:MD5 和 SHA1 还能用吗?

A:做 文件完整性校验 可以;做 密码哈希 基本禁止。推荐 bcrypt(自带 salt)、Argon2id(抗 GPU 暴力穷举)。

Q2:为什么 AES 需要 IV?

A:若没有随机 IV,同一明文 + 同一密钥会生成同一密文,攻击者可据此推断 数据规律 甚至实施重放攻击。

Q3:如何防止 AES 密钥在内存中被 dump?

A:可借助 @napi-rs/argon2 这类 C 拓展,把密钥存到进 C 堆而不是 V8 堆,降低被 Node.js 堆快照泄漏的风险。

Q4:Diffie-Hellman 的密钥长度怎么选?

A:许多行业规范建议 DH 至少 2048 位,等量 RSA 建议 3072 位开始。但如果你使用的是 ECDH(椭圆曲线),256 位就能达到类似安全水平且性能更优。

Q5:RSA 签名与加密有什么区别?

A:

Q6:生产环境要用到 HTTPS,证书管理能用 Crypto 吗?

A:完全可加载 PEM 证书做 校验,但证书部署与刷新仍建议交给 Nginx / Traefik / Caddy 这类反向代理,省时省力;只有在写 私有 CAIoT 设备端 TLS 通信 时才“深入” Crypto API。


小结与快速清单

任务推荐做法
密码存储bcrypt 或 Argon2id
Token 签名Hmac + Secret
通道对称加密AES-256-CBC + 随机 IV
小数据非对称加密RSA-2048 / RSA-4096
密钥交换ECDH-256

👉 直接体验加密世界里最常被忽视的安全细节

把以上五类算法组合起来,你就能在 Node.js 环境里搭出可扩展、可审计、跨语言互操作的安全模块。祝你写代码也像马拉松一样,节奏稳健、一骑绝尘!