如何在Postman里对参数进行SHA1WithRSA数字签名

如何在Postman里对请求参数进行数字签名

需求场景:最近做的一个支付网关项目,基于http协议接受请求参数,因此想到用postman来做联调和场景测试,postman的参数管理和请求分组编排比较方便。
但是请求需要做数字签名,也就是说要在发送请求之前对请求做加密签名处理。

问题所在

  1. postman自带的加密函数是cryptoJS,不能满足数字RSA-SHA1签名,即java里的SHA1WithRSA
  2. 因此需要接入第三方库,这里找到两个forge.js和jsrsasign.js
    • postman的接入方式
    • 签名代码的编写方式
  3. 要找到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

引入步骤及相关代码

  1. 下载forge.js,地址forge.js
  2. 下载nginx,将forge.js放到html目录下(ng都是默认的设置)
  3. 打开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

  • https://blog.csdn.net/u010320108/article/details/82871891

forge.js

  • https://github.com/loveiset/RSAForPostman
  • https://testerhome.com/topics/14869

jsrsasign

  • https://www.jianshu.com/p/78821648d6ff
  • https://juejin.im/post/59e41ece51882546b15b8dc9

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);

你可能感兴趣的:(如何在Postman里对参数进行SHA1WithRSA数字签名)