随着互联网技术的飞速发展,
数据安全
和隐私保护
成为了人们关注的焦点。前端加密作为保护用户数据安全的重要手段之一,其重要性日益凸显。本文将从加密技术的历史发展入手,介绍加密类型分类,并以CryptoJS
和JSEncrypt
两个流行的 JavaScript 加密库为例,详细介绍其 API 和使用示例。
现代加密分类
- 编码:不算加密,而是一种编码方式,我们直接看不懂,看着像加密,代表 Base64
- 哈希算法:虽然不是加密,但哈希函数可以用于
验证数据的完整性
。常见的哈希算法有如MD5、SHA
系列 - 对称加密算法:使用相同的密钥进行加密和解密。常见的对称加密算法有如
DES、AES
(高级加密标准) - 非对称加密算法:使用一对密钥,即
公钥和私钥
。公钥用于加密,私钥用于解密。常见的非对称加密算法有 RSA 和 ECC(椭圆曲线加密)
算法实例
Base64
Base64 是一种
编码方法
,它可以将二进制数据转换成 64 个可打印的 ASCII 字符的字符串
。这种编码方式常用于在不支持二进制数据的环境中传输数据,例如在 URL、cookie 或 HTML 中。在前端开发中,Base64 编码可以用于多种场景,例如图片的内联显示、发送数据到 API 等。
- Base64 编码 :
window.btoa
,在 JavaScript 中,可以使用 btoa 函数对文本数据进行 Base64 编码。对于二进制数据,可以使用window.btoa
函数,但需要先将二进制数据转换为字符串。
js
let text = "Hello, World!";
let base64Encoded = window.btoa(text);
console.log(base64Encoded); // 输出:SGVsbG8sIFdvcmxkIQ==
- Base64 解码 :
window.atob
如果需要将 Base64 编码的字符串解码回原始数据,可以使用 atob 函数
js
let base64Encoded = "SGVsbG8sIFdvcmxkIQ==";
let decodedText = window.atob(base64Encoded);
console.log(decodedText); // 输出:Hello, World!
安装准备
我们以 cryptoJS 来进行加密实例代码演示,先安装 cryptJS
js
npm i crypto-js @types/crypto-js
jsx
import CryptoJS from "crypto-js";
import { useEffect } from "react";
export default function App() {
useEffect(() => {
console.log(CryptoJS);
}, []);
return (
<div className="App">
<h1>加密数据</h1>
</div>
);
}
Hash(哈希) 算法
MD5 (Message Digest Algorithm 5)
- 特点 :快速且广泛使用,但已经不再被认为是安全的,因为它容易受到多种攻击,如碰撞攻击。
解决方式:二次/多次 MD5
js
let CryptoJS = require("crypto-js");
let message = "Hello, World!";
let hash = CryptoJS.MD5(message).toString();
console.log(hash); // 输出:e10adc3949ba59abbe56e057f20f883e
SHA-1 (Secure Hash Algorithm 1)
- 特点:比 MD5 更安全,但仍然存在一些安全问题,特别是对于高要求的安全性场景。已经被更安全的 SHA-2 和 SHA-3 算法所取代。
js
let CryptoJS = require("crypto-js");
let message = "Hello, World!";
let hash = CryptoJS.SHA1(message).toString();
console.log(hash); // 输出:2aa4f胆固醇7a5a7b5b5a6e7c5a5a5a6d
SHA-256 (Secure Hash Algorithm 256-bit)
- 特点:属于 SHA-2 家族,提供比 SHA-1 更高的安全性,是当前广泛使用的哈希算法之一。
- 用途:适用于需要较高安全性的场合,如密码存储、数据完整性验证等。
js
let CryptoJS = require("crypto-js");
let message = "Hello, World!";
let hash = CryptoJS.SHA256(message).toString();
console.log(hash); // 输出:5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8
SHA-3
- 特点:SHA-3 是第三代安全散列算法(Secure Hash Algorithm 3), SHA-3 可以配置输出散列长度为 224,256,384 或 512 位,默认为 512 位。
js
let hash = CryptoJS.SHA3("Message");
// outputLength : 224,256,384 或 512 位
let hash = CryptoJS.SHA3("Message", { outputLength: 512 });
PBKDF2 (Password-Based Key Derivation Function 2)
- 特点:基于密码的密钥派生函数,可以与多种哈希算法(如 SHA-1 或 SHA-256)结合使用,具有迭代次数的配置选项,以增加破解难度。
- 用途:常用于密码存储,因为它提供了一种安全的方式来派生密钥。
js
let salt = CryptoJS.lib.WordArray.random(128 / 8); // 随机盐
let key = CryptoJS.PBKDF2(message, salt, {
keySize: 8, // 密钥大小
iterations: 1000, // 迭代次数
});
let hash = salt.toString() + key.toString();
console.log(hash);
HMAC (Hash-based Message Authentication Code)
- 特点 :使用
哈希算法
与一个密钥结合
来提供消息的认证和完整性保护。
js
let CryptoJS = require("crypto-js");
let message = "hello world";
let key = "my key";
let hmac = CryptoJS.HmacSHA256(message, key);
let hmacHash = hmac.toString(CryptoJS.enc.Hex);
console.log(hmacHash); // 输出 HMAC 的十六进制字符串
在选择哈希算法时,需要根据应用的安全需求、性能要求以及兼容性来做出决定。对于数据完整性校验,可以选择 SHA-256 或 SHA-3 等算法。
对称加密
AES
(高级加密标准)是一种广泛使用的对称加密算法,用于保护数据安全。Crypto
库中的AES
加密可以确保数据在存储或传输过程中的机密性和完整性。
AES 加密参数解释:
- 密钥(Key) :AES 加密使用固定长度的密钥,可以是 128、192 或 256 位。
密钥的长度决定了加密的强度
。 - 选择模式 :AES 加密有多种模式(
mode
),如ECB
(电子密码本模式)、CBC
(密码块链接模式)、CTR
(计数器模式)等。每种模式都有其特定的用途和安全性。 - 初始化向量(IV, Initialization Vector):AES 加密中,除了密钥外,还有一个重要的组成部分是初始化向量。IV 用于确保即使相同的明文使用相同的密钥加密多次,也会产生不同的密文,从而增加加密的安全性。IV 的长度通常与块大小相同,即 128 位。
- padding(填充) : 是一种技术,用于处理明文数据,
使其长度符合加密算法的块大小要求
,AES 是基于块的,这意味着它们一次只能加密固定数量的比特。如果明文的长度不是块大小的整数倍,就需要使用填充来补足- PKCS5:这是一种常用的填充方式,它根据需要填充的字节数来填充数据。填充的字节将包含填充的字节数信息
- PKCS7 :这是一种常用的填充方式(
默认填充方式
),它根据需要填充的字节数来填充数据。填充的字节将包含填充的字节数信息 - ANSI X.923:与 PKCS#7 类似,但是当填充字节数小于块大小时,填充的第一个字节是 0x80,其余的填充字节是 0x00。
- ISO/IEC 7816-4:这种填充方式首先填充一个字节 0x80,然后填充 0x00 直到所需的填充长度,最后填充一个包含填充字节总数的字节。
- No:在某些情况下,如果明文的长度正好符合块大小,可以不使用填充。但是,这在实际应用中很少见,因为大多数情况下都需要处理长度不一的数据。
- Zero:简单地用 0 填充剩余的空间直到达到块大小。
- formatter:自定义输出格式
WordArray(数据类型)
WordArray
是 CryptoJS 中的一个核心数据类型,用于表示字(word)的数组。在 CryptoJS 中,一个字通常是 32 位的,即 4 个字节。WordArray
可以包含任意数量的字,并且可以进行各种操作,如加密、解密、哈希等。WordArray
是二进制数据的抽象表示,可以包含任意长度的数据,并且可以很容易地与其他数据类型进行转换。
转换示例:
-
将
string
转换为WordArray
:javascriptlet message = "Hello, World!"; let wordArray = CryptoJS.enc.Utf8.parse(message); // 使用Utf8编码将字符串转换为WordArray
-
将
WordArray
转换回string
:javascriptlet message = "Hello, World!"; let decryptedWordArray = CryptoJS.enc.Utf8.parse(message); let originalMessage = decryptedWordArray.toString(CryptoJS.enc.Utf8); // 将WordArray转换回字符串
AES 加密实例
javascript
let CryptoJS = require("crypto-js");
// 生成随机的密钥和IV let key = CryptoJS.lib.WordArray.random(128 / 8)
// 前后端约定好的
const key = CryptoJS.enc.Utf8.parse("ACC408B24462A333");
const iv = CryptoJS.enc.Utf8.parse("BBJNRU5666k4NzK6");
// 需要加密的明文
let plaintext = "hello word";
// 使用AES加密
let encrypted = CryptoJS.AES.encrypt(plaintext, key, {
iv: iv,
mode: CryptoJS.mode.CBC, // 使用CBC模式
padding: CryptoJS.pad.Pkcs7,
});
console.log(encrypted.toString()); // 输出加密后的密文
// 解密
let decrypted = CryptoJS.AES.decrypt(encrypted, key, {
iv: iv,
mode: CryptoJS.mode.CBC, // 使用相同的模式
padding: CryptoJS.pad.Pkcs7,
});
console.log(decrypted.toString(CryptoJS.enc.Utf8)); // 输出解密后的明文