🧑 博主简介:CSDN博客专家,历代文学网(PC端可以访问:https://literature.sinhy.com/#/?__c=1000,移动端可关注公众号 “ 心海云图 ” 微信小程序搜索“历代文学”)总架构师,
16年工作经验,精通Java编程,高并发设计,分布式系统架构设计,Springboot和微服务,熟悉Linux,ESXI虚拟化以及云原生Docker和K8s,热衷于探索科技的边界,并将理论知识转化为实际应用。保持对新技术的好奇心,乐于分享所学,希望通过我的实践经历和见解,启发他人的创新思维。在这里,我希望能与志同道合的朋友交流探讨,共同进步,一起在技术的世界里不断学习成长。
🤝商务合作:请搜索或扫码关注微信公众号 “心海云图”


现代 JavaScript 加密技术详解:Web Crypto API 与常见算法实践
关于JavaScript中的加解密及哈希操作,现代JavaScript环境主要通过 Web Cryptography API(浏览器)和 Node.js crypto模块(服务端)来提供支持。下面我将为你梳理它支持的编解码类型、MD5等常见算法的使用方法以及一些重要的实践建议。
这里用一个表格来概括 JavaScript crypto 支持的主要算法类型和常见算法:
| 算法类型 | 常见算法 | 主要用途 |
|---|---|---|
| 哈希(摘要) | MD5, SHA-1, SHA-256, SHA-512 | 生成数据唯一指纹,用于数据完整性校验、密码存储(需加盐)等。 |
| 对称加密 | AES (CBC, GCM, ECB 等模式) | 加密和解密使用相同密钥,适合加密大量数据,如文件加密、传输数据加密。 |
| 非对称加密 | RSA (OAEP 等模式) | 使用公钥加密、私钥解密,适用于身份验证和安全传输会话密钥。 |
| 其他操作 | 随机数生成 (crypto.getRandomValues) | 生成密码学安全的随机值,用于创建密钥、初始向量 (IV) 等。 |
🔐 哈希(摘要)算法
哈希算法能将任意长度的数据映射为固定长度的、唯一的哈希值,这个过程是不可逆的,所以没有“解密”一说。MD5就是一种常见的哈希算法。
认识 MD5
- 特点:输出固定长度为128位(32字符十六进制字符串),具有雪崩效应(输入微小变化导致输出巨大差异)。
- 安全性注意:MD5 已被证明存在碰撞漏洞(不同数据可能生成相同哈希值),不适用于高安全场景(如证书、金融交易)。对于密码存储和数据校验,更推荐使用 SHA-256 等更安全的算法。
如何使用 MD5
你有多种方式可以在 JavaScript 中计算 MD5 哈希值。
-
使用 Web Crypto API(现代浏览器原生支持)
现代浏览器提供了crypto.subtle接口,但它不支持 MD5 算法。对于 SHA 系列算法,以下是使用 Web Crypto API 计算 SHA-256 的例子:async function sha256Hash(text) { const encoder = new TextEncoder(); // 将字符串编码为Uint8Array const data = encoder.encode(text); // 使用Web Crypto API计算SHA-256哈希 const hashBuffer = await crypto.subtle.digest('SHA-256', data); const hashArray = Array.from(new Uint8Array(hashBuffer)); // 将哈希值转换为十六进制字符串 const hashHex = hashArray.map(b => b.toString(16).padStart(2, '0')).join(''); return hashHex; } // 使用示例 sha256Hash('Hello, World!').then(hash => console.log(hash)); -
使用 CryptoJS 库(支持MD5及其他多种算法)
如果你需要计算 MD5,或者希望代码在不同环境下有更好的兼容性,可以使用第三方库 CryptoJS。-
安装与引入
可以通过npm安装:npm install crypto-js。
或者在HTML中直接通过CDN引入:<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.2.0/crypto-js.min.js"></script> -
计算 MD5 示例
// 使用CryptoJS const md5Hash = CryptoJS.MD5('Hello, World!').toString(); console.log(md5Hash); // 输出MD5哈希值 -
计算 SHA-256 示例
const sha256Hash = CryptoJS.SHA256('Hello, World!').toString(); console.log(sha256Hash);
-
-
在 Node.js 中使用 crypto 模块
Node.js 内置了crypto模块用于加密操作。const crypto = require('crypto'); // 计算字符串的MD5 function md5Hash(text) { return crypto.createHash('md5').update(text).digest('hex'); } // 计算字符串的SHA-256 function sha256Hash(text) { return crypto.createHash('sha256').update(text).digest('hex'); } console.log(md5Hash('Hello, World!')); console.log(sha256Hash('Hello, World!'));
MD5的应用场景与安全讨论
-
典型应用场景:
- 文件完整性校验:计算文件MD5并与官方提供的哈希值比对,验证文件在传输过程中是否被篡改。
- 密码存储(需加盐):将用户密码进行MD5哈希后存储。但务必注意,单独使用MD5非常不安全,一定要配合盐值(Salt) 使用。
// 示例:加盐MD5 const password = 'user123'; const salt = 'random_salt_string'; // 盐值应由后端动态生成,并保证足够长且随机 const saltedPassword = password + salt; const hashedPassword = CryptoJS.MD5(saltedPassword).toString(); - 接口签名防篡改:将请求参数、时间戳和密钥拼接后计算MD5,作为签名随请求发送,服务器端按相同规则验证,确保请求在传输过程中未被修改。
-
安全最佳实践:
- 应对彩虹表攻击:务必使用加盐(Salt) 处理。
- 避免密钥前端暴露:关键签名操作应在后端生成,前端硬编码密钥极易被破解。
- 高安全场景:避免使用MD5,改用 SHA-256、HMAC,密码存储推荐使用 bcrypt 或 PBKDF2。
🔑 对称加密(以 AES 为例)
对称加密的特点是加密和解密使用同一个密钥,加解密速度快,适合处理大量数据。
AES 加密模式
AES 有多种工作模式,例如:
- CBC 模式 (Cipher Block Chaining):需要初始向量 (IV),安全性较高。
- GCM 模式 (Galois/Counter Mode):同时提供加密和认证功能。
- ECB 模式 (Electronic Codebook):简单但不安全,不推荐使用。
使用 CryptoJS 进行 AES 加解密
以下是一个使用 CryptoJS 进行 AES-CBC 加密解密的完整示例:
import CryptoJS from 'crypto-js';
// 准备工作:密钥和初始向量(IV)
// 密钥和IV都应该是16字节(对应128位 AES)。生产环境中,密钥应从后端安全获取,切勿硬编码。
const SECRET_KEY = CryptoJS.enc.Utf8.parse('your-16byte-key!!');
const IV = CryptoJS.enc.Utf8.parse('your-16byte-iv__');
/**
* AES-CBC 加密函数
* @param {any} data - 需要加密的数据(可以是对象、字符串等)
* @returns {string} 加密后的Base64编码字符串
*/
export function encrypt(data) {
try {
// 统一将数据转换为字符串
const jsonData = typeof data === 'string' ? data : JSON.stringify(data);
// 执行加密
const encrypted = CryptoJS.AES.encrypt(jsonData, SECRET_KEY, {
iv: IV,
mode: CryptoJS.mode.CBC, // 使用CBC模式
padding: CryptoJS.pad.Pkcs7 // 使用PKCS7填充
});
// 返回Base64格式的密文
return encrypted.toString();
} catch (error) {
console.error('加密失败:', error);
return '';
}
}
/**
* AES-CBC 解密函数
* @param {string} encryptedData - 加密后的Base64字符串
* @returns {any} 解密后的原始数据(对象或字符串)
*/
export function decrypt(encryptedData) {
if (!encryptedData) return null;
try {
// 执行解密
const decrypted = CryptoJS.AES.decrypt(encryptedData, SECRET_KEY, {
iv: IV,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
});
// 将解密结果转换为UTF8字符串
const originalText = decrypted.toString(CryptoJS.enc.Utf8);
// 尝试解析为JSON对象(如果原始数据是对象)
try {
return JSON.parse(originalText);
} catch {
// 解析失败则直接返回字符串
return originalText;
}
} catch (error) {
console.error('解密失败:', error);
return null;
}
}
// 使用示例
const originalInfo = { user: 'Alice', id: 123 };
const encryptedText = encrypt(originalInfo);
console.log('加密结果:', encryptedText);
const decryptedText = decrypt(encryptedText);
console.log('解密结果:', decryptedText);
使用 Web Crypto API 进行 AES 加解密
对于现代浏览器,你可以使用原生的 Web Crypto API 进行 AES-GCM 加密:
const encoder = new TextEncoder();
const decoder = new TextDecoder();
/**
* 生成一个用于AES-GCM算法的密钥
*/
async function generateAESKey() {
return await crypto.subtle.generateKey(
{
name: "AES-GCM",
length: 256, // 密钥长度:256位
},
true, // 密钥是否可提取
["encrypt", "decrypt"] // 密钥用途
);
}
/**
* 使用AES-GCM加密数据
* @param {CryptoKey} key - 生成的密钥
* @param {string} data - 要加密的明文
* @returns {Object} 包含密文和初始向量(IV)的对象
*/
async function encryptAES(key, data) {
const encoded = encoder.encode(data);
// 生成随机的12字节初始向量(IV)
const iv = crypto.getRandomValues(new Uint8Array(12));
const encrypted = await crypto.subtle.encrypt(
{
name: "AES-GCM",
iv: iv
},
key,
encoded
);
return { encrypted, iv };
}
/**
* 使用AES-GCM解密数据
* @param {CryptoKey} key - 用于解密的密钥
* @param {ArrayBuffer} encryptedData - 密文数据
* @param {Uint8Array} iv - 初始向量
* @returns {string} 解密后的明文
*/
async function decryptAES(key, encryptedData, iv) {
const decrypted = await crypto.subtle.decrypt(
{
name: "AES-GCM",
iv: iv
},
key,
encryptedData
);
return decoder.decode(decrypted);
}
// 使用示例
(async () => {
const key = await generateAESKey();
const originalData = "这是一段秘密信息";
const { encrypted, iv } = await encryptAES(key, originalData);
console.log("加密结果:", new Uint8Array(encrypted));
const decryptedData = await decryptAES(key, encrypted, iv);
console.log("解密结果:", decryptedData);
})();
🗝️ 非对称加密(以 RSA 为例)
非对称加密使用一对密钥:公钥和私钥。公钥用于加密,私钥用于解密。Web Cryptography API 也支持 RSA 算法。
使用 Web Crypto API 生成密钥对与加解密
/**
* 生成RSA-OAEP密钥对
*/
async function generateRSAKeyPair() {
return await crypto.subtle.generateKey(
{
name: "RSA-OAEP",
modulusLength: 2048, // 密钥长度
publicExponent: new Uint8Array([1, 0, 1]), // 公共指数:65537
hash: "SHA-256", // 与密钥一起使用的哈希函数
},
true, // 密钥是否可提取
["encrypt", "decrypt"] // 密钥用途
);
}
/**
* 使用公钥加密数据
* @param {ArrayBuffer} publicKey - 公钥
* @param {string} data - 要加密的明文
* @returns {ArrayBuffer} 密文
*/
async function encryptWithRSA(publicKey, data) {
const encoder = new TextEncoder();
const encoded = encoder.encode(data);
return await crypto.subtle.encrypt(
{ name: "RSA-OAEP" },
publicKey,
encoded
);
}
/**
* 使用私钥解密数据
* @param {CryptoKey} privateKey - 私钥
* @param {ArrayBuffer} encryptedData - 密文
* @returns {string} 解密后的明文
*/
async function decryptWithRSA(privateKey, encryptedData) {
const decoder = new TextDecoder();
const decrypted = await crypto.subtle.decrypt(
{ name: "RSA-OAEP" },
privateKey,
encryptedData
);
return decoder.decode(decrypted);
}
// 使用示例
(async () => {
// 生成密钥对
const { publicKey, privateKey } = await generateRSAKeyPair();
const message = "这是一条秘密消息";
// 加密
const encrypted = await encryptWithRSA(publicKey, message);
console.log("RSA加密后的数据:", new Uint8Array(encrypted));
// 解密
const decrypted = await decryptWithRSA(privateKey, encrypted);
console.log("RSA解密后的数据:", decrypted);
})();
⚠️ 重要安全提示与实践建议
在JavaScript中进行加解密操作时,务必牢记以下安全准则:
- 前端加密不能替代HTTPS:前端代码和传输的密文仍有被截获和篡改的风险。HTTPS 是保障通信安全的基础,前端加密只能作为额外防护手段。
- 永远不要硬编码密钥:将密钥直接写在前端代码中极易被他人获取。生产环境中,密钥应通过安全的后端接口动态获取。
- 使用强随机数:生成密钥、初始向量(IV)、盐值(Salt)时,务必使用密码学安全的随机数生成器,如
crypto.getRandomValues()。 - 妥善管理密钥:遵循最小权限原则,定期轮换密钥。公钥和私钥要分开存储,私钥必须保存在安全的服务器端,严禁泄露。
- 选择正确的算法:
- 哈希:避免使用MD5、SHA-1,推荐 SHA-256、SHA-512。密码存储推荐使用 bcrypt、PBKDF2 或 Argon2。
- 对称加密:推荐 AES-GCM 或 AES-CBC 模式,并确保使用随机且唯一的IV。
- 非对称加密:推荐 RSA-OAEP 或基于椭圆曲线的 ECC。
💎 总结
总的来说,JavaScript 通过 Web Cryptography API 和 Node.js crypto 模块提供了强大的加密能力。MD5作为一种哈希算法,因其自身安全性问题,不推荐在高安全场景下使用,但了解其原理和实现对于学习其他加密算法仍有帮助。在实际开发中,请务必根据你的具体需求(是要求完整性校验、机密性还是身份认证)选择合适的算法,并严格遵守安全实践。
1044

被折叠的 条评论
为什么被折叠?



