之前参与的一个项目采用的是NodeJs+MongoDB数据库全栈开发,连接MongoDB数据库地址是写在nodejs的配置文件中实现调用,此前配置的数据库地址url的账号密码和IP地址是文明显示的,从安全性角度来看,如同在“裸奔”般危险。
为解决安全通报 〔2019〕05号工作要求AQ011项【严禁密钥/密码/口令等以明文形式存储在数据库、代码或配置文件中】,我们使用node-rsa对nodejs配置文件中存在的明文进行加密,下面来总结一下简单的rsa加密解密用法。
初始化环境
新建一个文件夹 node-rsa-demo , 终端进入,运行下面命令初始化
cd node-rsa-demo
npm init # 一路回车即可
npm install --save node-rsa
生成公钥私钥
先在 node-rsa-demo 文件夹下新建一个文件夹 pem 用来存放密钥的
然后再新建一个文件 index.js 写上如下代码
var NodeRSA = require('node-rsa')
var fs = require('fs')
function generator() {
var key = new NodeRSA({ b: 512 })
key.setOptions({ encryptionScheme: 'pkcs1' })
var privatePem = key.exportKey('pkcs1-private-pem')
var publicPem = key.exportKey('pkcs1-public-pem')
fs.writeFile('./pem/public.pem', publicPem, (err) => {
if (err) throw err
console.log('公钥已保存!')
})
fs.writeFile('./pem/private.pem', privatePem, (err) => {
if (err) throw err
console.log('私钥已保存!')
})
}
generator();
接着执行 node index.js ,结果如图:
然后你会发现在 pem 文件夹下生成了两个文件,即公钥和私钥
- private.pem
- public.pem
加密
加密配置文件config.db.url这个字符串
function encrypt() {
fs.readFile('./pem/private.pem', function (err, data) {
var key = new NodeRSA(data);
let cipherText = key.encryptPrivate('mongodb://limoumou:[email protected]:8080/web', 'base64');
console.log(cipherText);
});
}
encrypt();
然后执行 node index.js 终端里会输出一串字符,结果如图:
jKonGONf+RDzcrMj7kPjyV68CuR7ipY7nBII9D2jO2+qZPY5oNxUlX57cVObYAhjTxowdbu3yb81XgGTNV94npPKtti78q68GVR3z46VuFAvYuS/it2JaeYB13OvEng9EchBa.........cwlGX+ATwhtDeZirf0S6rwdBg+y4RIvgkaM 的base64字符串,这就是用私钥加密后的密文了
解密
把上一步加密获得的密文复制粘贴到下面要解密的方法内
function decrypt() {
fs.readFile('./pem/public.pem', function (err, data) {
var key = new NodeRSA(data);
let rawText = key.decryptPublic('jKonGONf+RDzcrMj7kPjyV68CuR7ipY7nBII9D2jO2+qZPY5oNxUlX57cVObYAhjTxowdbu3yb81XgGTNV94npPKtti78q68GVR3z46VuFAvYuS/it2JaeYB13O......cwlGX+ATwhtDeZirf0S6rwdBg+y4RIvgkaM', 'utf8');
console.log(rawText);
});
}
decrypt();
执行 node index.js
会发现又拿到 mongodb://limoumou:[email protected]:8080/web
这个数据库地址了
但是
fs.readFile()为异步加载方式,运行后rawText参数始终为空
try {
mongoose.connect( rawText, {useMongoClient: true}, function(err) {
if (err) {
console.log('数据库连接失败!');
} else {
console.log('数据库连接成功!');
}
});
} catch (error) {
console.log(error);
}
报错提示为:Error: Invalid mongodb uri "". Must begin with "mongodb://",即先执行了数据库链接命令后执行解密操作
优化
采用fs.readFileSync()同步来读取公钥文件,优化如下:
var NodeRSA = require('node-rsa');
var key = new NodeRSA();
let rawText = '';
var publicData = fs.readFileSync('./pem/public.pem');
key = new NodeRSA(publicData);
var longString = config.db.url;
rawText = key.decryptPublic(longString, 'utf8');
这样即可正确执行连接数据库命令,到这里就算是完成了NodeJs加密解密配置文件数据库明文地址的问题,Over
改进
当目标任务完成,我们更多的,还要考虑程序的性能,运行效率,组织结构,和重用性等等。
以上到优化步骤的解决方案存在一个问题,网站在运行过程中会不断的请求数据库,那么就会不断的进行解密的操作,改进方案即是把加密解密的操作单独写在一个rsa.js放置在中间件中,解密后的值以参数的形式传送过来。