这是我参与8月更文挑战的第21天,活动详情查看:8月更文挑战
加解密
前端调用接口和后端进行通信的过程,其实是数据传输的过程。
在这个过程中,会有很多意外的情况发生,典型的比如中间人劫持攻击,前段时间都*和吴*的事件就好比典型的中间人劫持攻击。
在传统的 http 请求下,数据都是明文传输的,前后端包括中间人都是所见即所得,这样难以保证数据不会被泄漏。
所以解决的办法是很多程序都是部署了 https 的协议。
那如果没有部署 https 的接口呢?一般都会将比较敏感的数据使用数据加密的方法进行传输。
而且不仅仅是数据传输的阶段,在数据存储上,重要的数据也是加密存储的。相信大家都了解过数据库泄漏等安全问题。
说到加解密,有很多方法。例如 jsencrypt、md5 等等。这篇博客说的 crypto 也是类似的,不同点是 crypto 是 nodeJs 的一个模块,类似 fs。
crypto
crypto 是 node 内置的模块,提供了加密功能,其中包括了用于 OpenSSL 散列、HMAC、加密、解密、签名、以及验证的函数的一整套封装。
在没有使用 crypto 之前,我们的前端用的是 jsencrypt 做加密,后端则用 node-rsa 做解密,公钥和私钥都是通过 node-ras 生成的,代码如下
const NodeRSA = require('node-rsa')
let key = new NodeRSA({ b: 1024 })
key.setOptions({ encryptionScheme:'pkcs1'})
let pubkey = key.exportKey('public') //生成公钥,发给前端用于数据加密
let privkey = key.exportKey('private')//生成私钥,用于数据解密
解密的代码也很简单
let key = new NodeRSA(privkey)
key.setOptions({ encryptionScheme: 'pkcs1' })
//encryptData是加密后的数据
const encryptData = 'damkiuh34r09u323rbnavjaf9uerjfqefqqb09023h43ibcae9uoue5bin'
const s = encryptData.replace(/\s+/g, '+')
const decryptData = key.decrypt(s, 'utf8')
这里前端使用 jsencrypt 对数据加密的逻辑我就略过了。不过 node-rsa 不是 nodeJs 固有的模块,使用前需要提前安装
npm install node-rsa
crypto 是 node 的内置模块,因此我后面选择了 crypto 重写了数据加解密的逻辑。
加解密的过程十分简洁:
- 生成加解密需要的的公钥和私钥
- 使用公钥对数据加密
- 使用私钥对数据解密
代码
我们先实现生成公钥和私钥的代码
const { generateKeyPairSync, publicEncrypt, privateDecrypt } = require('crypto')
const { publicKey, privateKey } = generateKeyPairSync('rsa', {
modulusLength: 1024,
publicKeyEncoding: {
type: 'spki',
format: 'pem'
},
privateKeyEncoding: {
type: 'pkcs8',
format: 'pem'
}
});
接下来尝试对一段数据进行加密
//需要加密的数据
const data = "data to crypto"
const pub = publicKey.toString('ascii')
// 公钥加密过程
const encryptData = publicEncrypt(pub, Buffer.from(data)).toString('base64');
console.log('encode:', encryptData);
得到加密的结果,是一段 base64 的字符串
encode: Me+2EbDsMVLQHPKR8ZB3K88EDs4jNKuHsAZzMIjY3DCO7JEJGu3Tfkwv0tX4kDMiQvrxyJkR7tlpHQ1f91BrweAK6mkeyeyNQ3XOfsHwIEZJB+iv8IZpKiIlyE1KOGaUsN2Q8MyTRZ86IF+Qj4MwotDggXH/ADAHC0oJB/D5H5s=
然后对加密后的数据进行解密
const pri = privateKey.toString('ascii')
// 私钥解密
const decryptData = privateDecrypt(pri, Buffer.from(encryptData.toString('base64'), 'base64'));
console.log('decode:', decryptData.toString());
解密的结果
decode: data to crypto
从上面的代码可以看出加密和解密只需要分别调用publicEncrypt和privateDecrypt这两个函数即可,而这两个函数,正是内置模块 crypto 对外抛出的方法。
这样看来,加解密的过程是不是更简单一些呢~