如何在Postman里对请求参数进行数字签名
需求场景:最近做的一个支付网关项目,基于http协议接受请求参数,因此想到用postman来做联调和场景测试,postman的参数管理和请求分组编排比较方便。
但是请求需要做数字签名,也就是说要在发送请求之前对请求做加密签名处理。
问题所在:
- postman自带的加密函数是cryptoJS,不能满足数字RSA-SHA1签名,即java里的SHA1WithRSA
- 因此需要接入第三方库,这里找到两个forge.js和jsrsasign.js
- postman的接入方式
- 签名代码的编写方式
- 要找到java里的SHA1WithRSA对应的js里加密签名的实现方式,这个地方很不好确认。SHA1WithRSA叫法是java里的,在jsrsasign里也叫SHA1WithRSA,
但在forge里就是sha1,这里是一点点试验出来的。如果还不能解决,只能使用openssl加密,但学习曲线就比较麻烦了,这是万不得已之选。
postman的接入方式
postman似乎没有很好的接入第三方库的方式,postman自身设计很庞大了,几十兆的安装包和几百兆的运行内存,实际上就是一个node环境的ide了。但接入方式有限。
接入方式大概有两种:
1.将js文件内容设置为global变量,eval执行js,但是这种方案似乎会导致很卡,我没有尝试
2.提供一个可以访问到js的web地址,如将js文件放到一个nginx下面,通过postman 发送请求获取js,设置为gloable变量,然后eval
这里选择的第二种方案。可以看到,这两种方案本质上都是设置为全局变量,然后eval执行js,这就要求js得打包支持eval,如果js文件打包有问题,或者像jsrsasign
不提供打包成一个js文件的,就很难接入。
软件环境
- postman:
- nodeJS
引入步骤及相关代码
- 下载forge.js,地址forge.js
- 下载nginx,将forge.js放到html目录下(ng都是默认的设置)
- 打开postman,在
pre-script
里输入如下代码:
console.log(pm.globals.has("forgeJS"));
if(!pm.globals.has("forgeJS")){
pm.sendRequest("http://127.0.0.1/forge.js", function (err, res) {
if (err) {
console.log(err);}
else {
pm.globals.set("forgeJS", res.text());}
})}
eval(pm.globals.get("forgeJS"));
// console.log(pm.globals.get("forgeJS"));
//注意此处上下的BEGIN PRIVATE KEY不要删除,框架自带的
const private_key = '-----BEGIN PRIVATE KEY-----\n' +
'此处填写你的密钥字符串' +
'-----END PRIVATE KEY-----'
var privKey = forge.pki.privateKeyFromPem(private_key);
const md = forge.md.sha1.create();//这里的sha1对应的java的SHA1WithRSA
let _buffer='这里填写需要加密的参数串';
md.update(_buffer,"utf8");
let sig = privKey.sign(md);
let erg = forge.util.encode64(sig);
console.log("Signature is: "+erg);
其他问题记录
- 这里出现过一个问题,我通过forge官方的打包教程,自己通过npm install了forge,自己打包,最后打的包有问题,eval一直不成功。后来是直接用github上他们
自己提供的已打包好的forge.js才成功了。此处,替换前,需要删除错误的js文件全局变量,使用代码: pm.globals.unset("forgeJS"); - 加密方式自己多尝试
相关资料
cryptoJS
forge.js
jsrsasign
nodejs或openssl
-
https://www.zhihu.com/question/43367849
- RSA-SHA1 和 SHA1WithRSA 是不是一样的(我感觉是一样的)
- crypto 模块不过是 OpenSSL 的 wrapper
- 想知道 crypto 支持什么算法,就去看 OpenSSL 的文档, man openssl(所以crptoJS也是支持SHA1的?)
完整代码:
let param = request.data;
console.log(param);
let paramStr = "";
// param.time = (new Date()).getTime().toString();
param = objSort(param);
console.log(param)
for (let i in param) {
if (i == "sign" || i == "sign_type") {
continue;
}
paramStr += i+"="+param[i] +"&";
}
paramStr = paramStr.substring(0, paramStr.length - 1);
console.log(paramStr);
function objSort(obj)
{
let keys = Object.keys(obj).sort();
let arr = {};
for (let i in keys) {
arr[keys[i]] = obj[keys[i]];
}
return arr;
}
// pm.globals.unset("forgeJS");
console.log(pm.globals.has("forgeJS"));
if(!pm.globals.has("forgeJS")){
pm.sendRequest("http://www.xxx.cn/forge.js", function (err, res) {
if (err) {
console.log(err);}
else {
pm.globals.set("forgeJS", res.text());}
})}
eval(pm.globals.get("forgeJS"));
// console.log(pm.globals.get("forgeJS"));
// eval(postman.getGlobalVariable("forgeJS"));
const private_key = '-----BEGIN PRIVATE KEY-----\n' +
'yourrivatekey' +
'-----END PRIVATE KEY-----'
// console.log(forge);
//encrypt text "plaintext"
var privKey = forge.pki.privateKeyFromPem(private_key);
const md = forge.md.sha1.create();
let _buffer='api_name=zhk.trade.query&app_auth_token=201603BBaf2dfb9a12954f09b7d356bd6b19bD26&biz_content={"inst_no":"18100001","mch_id":"1099219021210321","out_trade_no":"1543740545622","pay_type":"WECHAT"}&charset=UTF-8&service_name=yunzongxinxi&sign_type=RSA×tamp=1458896291111&version=1.0';
md.update(paramStr,"utf8");
let sig = privKey.sign(md);
let erg = forge.util.encode64(sig);
console.log("Signature is: "+erg);