明文传一个手机号怎么了,反正都开户了
0.前言
某次面试了一家银行的前端,被问到了关于前端安全方面的问题,具体就是前端如何做好加密解密,尤其是涉及到了用户信息,比如用户的手机号、身份证号之类的数据怎么处理。这确实是一个很重要的问题,尤其在金融类项目中,对数据安全性要求极高。今天就来详细讲解前端加密解密的相关知识。
1.CryptoJS
首先需要了解一下CryptoJS:这是一个强大的加密库,提供了多种加密算法,包括 AES、MD5、SHA 等。在前端项目中使用非常广泛。
1.1 基础使用
// 引入
import CryptoJS from 'crypto-js';
// 加密
function encrypt(data, key) {
return CryptoJS.AES.encrypt(data, key).toString();
}
// 解密
function decrypt(encryptedData, key) {
const bytes = CryptoJS.AES.decrypt(encryptedData, key);
return bytes.toString(CryptoJS.enc.Utf8);
}
// 使用示例
const key = 'secret key 123';
const text = '要加密的内容';
const encrypted = encrypt(text, key);
console.log('加密后:', encrypted);
const decrypted = decrypt(encrypted, key);
console.log('解密后:', decrypted);
1.2 进阶使用
// 使用CBC模式的AES加密
const encrypted = CryptoJS.AES.encrypt('hello', 'key', {
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7,
iv: CryptoJS.enc.Utf8.parse('1234567890123456')
}).toString();
// 对应的解密
const decrypted = CryptoJS.AES.decrypt(encrypted, 'key', {
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7,
iv: CryptoJS.enc.Utf8.parse('1234567890123456')
}).toString(CryptoJS.enc.Utf8);
1.3 其他功能
// MD5哈希
const md5Hash = CryptoJS.MD5('要哈希的内容').toString();
// SHA256哈希
const sha256Hash = CryptoJS.SHA256('要哈希的内容').toString();
// Base64编码
const base64 = CryptoJS.enc.Base64.stringify(CryptoJS.enc.Utf8.parse('hello'));
2.AES对称加密
AES是一种对称加密算法,所谓对称加密,就是加密和解密使用相同的密钥。就像一把钥匙开一把锁,这个钥匙既可以用来锁门,也可以用来开门。
AES加密有几种不同的工作模式:
2.1ECB模式
最简单的加密模式,但安全性较低,因为相同的明文会产生相同的密文。
const encryptedECB = CryptoJS.AES.encrypt('hello', 'key', {
mode: CryptoJS.mode.ECB
}).toString();
2.2 CBC模式
更安全的加密模式,需要提供一个初始向量(IV),相同的明文会产生不同的密文。
const encryptedCBC = CryptoJS.AES.encrypt('hello', 'key', {
mode: CryptoJS.mode.CBC,
iv: CryptoJS.enc.Utf8.parse('1234567890123456')
}).toString();
对称加密的优点是速度快,适合加密大量数据,但缺点是密钥的传输和保管比较困难。因为如果把秘钥直接写到前端项目中,可能会有泄露的风险。
在实际的项目中,比较推荐使用CBC模式,更加的安全可靠。
3.RSA非对称加密
RSA是一种非对称加密算法,它使用一对密钥:公钥和私钥。公钥可以公开给任何人,用于加密数据;而私钥必须严格保密,用于解密数据。
3.1 基本原理
使用公钥加密的数据只能用私钥解密,这就保证了数据的安全性。即使黑客获取了公钥,也无法解密数据。
3.2 使用场景
RSA主要用于:
- 加密密钥的传输
- 数字签名
- 加密敏感信息(如密码)
3.3 示例代码
// 使用公钥加密
const encrypted = crypto.publicEncrypt(
publicKey,
Buffer.from('要加密的内容')
).toString('base64');
// 私钥解密在服务器端进行
4.实际项目中的应用
在实际项目中,尤其是金融类项目,通常会结合使用这两种加密方式。让我们来看几个具体的场景:
(具体使用哪种方式,还是要看项目的要求,可以只使用AES,也可以只使用RSA,当然也可以两个结合一起)
AES的例子就不列举了,前面列举过了。
4.1 密码加密
密码直接使用 RSA 加密就可以了,原因是:
- 密码数据量小,RSA 的性能问题影响不大
- 密码安全要求高,需要更强的加密方式
- 只需要从客户端传到服务器,不需要双向通信
- 使用公钥加密,私钥解密的方式非常适合密码传输
// 从服务器获取公钥
async function getPublicKey() {
const response = await fetch('/api/getPublicKey');
const { publicKey } = await response.json();
return publicKey;
}
// 加密密码
async function encryptPassword(password) {
const publicKey = await getPublicKey();
return crypto.publicEncrypt(
publicKey,
Buffer.from(password)
).toString('base64');
}
4.2 敏感信息传输
对于身份证号、银行卡号等敏感信息,通常使用 AES + RSA 的组合加密方式:
class SecurityService {
async encryptSensitiveData(data) {
// 1. 生成随机的 AES 密钥
const aesKey = CryptoJS.lib.WordArray.random(16).toString();
// 2. 用 AES 加密数据
const encryptedData = CryptoJS.AES.encrypt(JSON.stringify(data), aesKey, {
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7,
iv: CryptoJS.enc.Utf8.parse('1234567890123456')
}).toString();
// 3. 用 RSA 加密 AES 密钥
const publicKey = await this.getPublicKey();
const encryptedKey = crypto.publicEncrypt(
publicKey,
Buffer.from(aesKey)
).toString('base64');
// 4. 返回加密后的数据和密钥
return {
data: encryptedData,
key: encryptedKey
};
}
}