前言
近期由于客户现场出现了非法接口的调用,为了处理此类问题和杜绝后续问题的出现。针对公司现有的项目实现接口加密,防止接口被恶意的调用。
设计思路:客户端存储超级私钥,客户端返回加密的公钥。客户端先使用超级私钥对公钥进行解密,使用解密出来的公钥对接口进行加密。把加密后的字符串进行验签发送给服务器,服务器进行字符串对比。
相关引用文件
文件的引用这里就只放截图了,源文件网上很容易找到的。这里使用jsencrypt.min.js
是为了节省小程序的空间。
获取服务器的加密公钥
var baseURL = require('./api.js');
var superPrivateKey = "MIIEpQIBAAKCAQEAyNftZEtP9PdwCZT8ZE8xSzuLA8tSZbczwBaLg+NiWKibCGsk11YXYcL8kZ9DBxVdpv1ysp7vGBu6QdmDKeymeae6HCEu3ThDjzGMbCCITswIWjT01Y7Fa6MQlbYJZD55MY3w/ZWDnzsjuTF6l3KJodqUwhXUlUvTbi60gdQXOmgNUE3LkGc9dsDonKBId46WLMY92B3vlLoA/GArBeCZQcwF29ztfrfvRP2tCtvV9tsqoRXSJXzbEgI3fX2/WVt9drXgMd9ZekM53PZwwEHQyEwnLrilOTAzlmzGO2ZbXY+4ahUo2iOH5WAvA65Y/qw7QgIzT24ooJ1HY1eyyFJUnwIDAQABAoIBAQC0lWF/Yi/8RFbaZrkgwAvEZz8xJClsB3NibWL4LQUKTl9HDH9NlrzjS9yoWph7z/wq34u3iyvTc2rfNmG22m88x1CRZkyq36HvKE/oEMA+iTmhUigptHtRsoaA9fIvzfROWB+tAjgcfaI7K3/cmEGj49MJR3Oi4VCzqw7mBPr1qWvNFx5vd4Rwjy4qO5K+BAlx8+yQ87z04tULlzUqBPIPK8WGb98TlG1CmMw5/ZQo1HfjxA82+8AO3qMapPDC6hzUBPvS+AQ2NxRdjceDxPmNzA2s2Kp2DIN3sQalSSy3+9ESLQpwwLhSJSmX/6E1XZFhv76nd3zOtbSUrzLBwzuxAoGBAPaVYfGMod/9eAZGQsCSv3sGQSis//jhjtHxef3VMdhGr3vgCmokLb1RlP50zVYlXYh3qvksn7ZjC5XkVbVDofNC4MJatzi4rIpQ/uUNmlxMMhZkwn8S4C9gIgkxXsY4siSb4zNKT6SxOFazi4qeMbwE+PlaYe2mxwl+iizw4slDAoGBANCDYwNEVFUE6F+ver9Lt25mBVP8L+pOjXSCGb3c9M2YvKVKuEZcOAwE/HnZms5xLAZGG7SCVbkLCUlOHoKigbKYr1jEvujMhbSF0IuhXHSnuvWmUX1HSo/bzdEyLEaQyZ+G2bQpYYUgKjEtfPcbHuDelUw99JY3ghoV04vv3DN1AoGBAK66JaAK/f2BV1Zi3RQmKEbdpLhU9kD+W7yKdt4V/u75D4ogtGCH6F1ZfNFeJM5hRcjYuy87nqSXxHLfTJhYJ17/ydIOg/xOZ/zO7f+SxwmV+HwDxApVbsRDQ3ruH/En5ZupVrJWet8BsSFGsp9z/1vyzhWrJO9ImYsxvmmf+6OPAoGALlMCTFeB5OGSPq/dtWI8/mnsBRyiCIwrIRdGYMgWGxcz0gUnq3oReZoh/XA61GKQRVSOEyxhnxq0lXSlkqBH8EW7rx0GzPGjQtf33Q2cXM5m2ux4bjzIc+2BbFiZPZQtNyPeegg3gjwDI6nXeY6s7YiF4spg7H6oiOMQfKZtZYECgYEAttlJveIjoMWNrnPWeegZ0VU+6HT7A4okcIIE0CLEmE9qVLoGGnehgpntf71spCePJOJhaPydZsDZPSrz916gHtg1vGwoApAgecweom3s95hKyOMsN6LoZRvrR7mx9UQ4Qjaq8bZzzxhF+XsvzC9QYBVUzeZp6y2rkXgKktBQ37c="
var Encrypt = require('../utils/jsencrypt.min.js');
var encryptor = new Encrypt.JSEncrypt();
function timest() {
let tmp = Date.parse(new Date()).toString();
tmp = tmp.substr(0, 10);
return tmp;
}
function getPrivatekey() {
return new Promise(function(resolve, reject) {
let time = timest();
wx.request({
url: baseURL.baseURL + 'api/services/app/Setting/GetCerPriKeyAsync?timestamp=' + time,
data: '',
header: {
},
method: 'Get',
success: function(res) {
encryptor.setPrivateKey(superPrivateKey);
let array = res.data.Result.Data;
let sourcePrivate = '';
for (let a = 0; a < array.length; a++) {
// sourcePrivate = encryptor.decrypt(array[0]) + array[1];
if (a == 0) {
sourcePrivate += encryptor.decrypt(array[a]);
} else {
sourcePrivate += array[a];
}
}
console.log("原始私钥" + sourcePrivate);
resolve(sourcePrivate);
},
fail: function(res) {
console.log(res)
reject(res)
},
complete: function(res) {
},
})
});
}
module.exports = {
getPrivatekey: getPrivatekey
}
baseURL
是定义接口地址,在获取加密公钥的时候由于RSA
自身的限制解密的字节大小最多是128
个。所以在此处采用分段解密,同时为了优化小程序首次的等待时间。只返回部分公钥,并且只有第一段公钥是加密的。这在很大程度上减少了等待的时间,让用户的体验更为流畅。
在这里将获取加密公钥的方法封账成一个Promise
方法,是为了保证小程序进行编译的时候在app.js
尚未执行完成的情况先,index.js
中的方法进行先行调用时没有公钥的情况。
处理首次获取加密公钥失败的情况
//app.js
// 引入请求文件
const http = require('/server/request.js');
const sm2 = require('/server/sm2.js');
const api = require('/server/api.js');
const util = require('/utils/weapp.js');
App({
globalData: {
uuid: ''
},
onLaunch: function(e) {
this.init();
this.globalData.uuid = wx.getStorageSync('uuid');
wx.clearStorageSync();
wx.setStorageSync('uuid', this.globalData.uuid);
},
// 初始化
async init() {
await this.getPrivatekey(); // 请求数据
this.getHomeSetting(); // 等待请求数据成功后
this.checkUpdateVersion(); //更新版本号
},
// 获取系统设置
getHomeSetting() {
let that = this;
http.requestLoading('api/services/app/CRMMemberService/GetHomeSetting', {
}, 'GET').then(res => {