前端請求參數MD5加密校驗,參數串解密

首先引入MD5加密庫:=>https://cdn.bootcss.com/blueimp-md5/2.10.0/js/md5.min.js;css

  步驟:=》1.請求前對參數進行字典升序排序,排序函數 小程序

function objKeySort(obj) {
var newkey = Object.keys(obj).sort();
//先用Object內置類的keys方法獲取要排序對象的屬性名,再利用Array原型上的sort方法對獲取的屬性名進行排序,newkey是一個數組
var newObj = {};//建立一個新的對象,用於存放排好序的鍵值對
for (var i = 0; i < newkey.length; i++) {//遍歷newkey數組
newObj[newkey[i]] = obj[newkey[i]];//向新建立的對象中按照排好的順序依次增長鍵值對
}
return newObj;//返回排好序的新對象
}

      2.排序後對參數進行校驗,校驗參數涉及簽名的請求頭=》api

oncekey 客戶端生成臨時隨機數6-8位字母或數字
timestr timestr時間戳
signkey 請求籤名key
wxsmall 對隨機生成的oncekeyMD5

      並將oncekey 與timestr鏈接進行MD5,得到hash字符串 將hash與datastr鏈接進行md5,datastr需引用函數objtostring將其轉化爲字符串,獲得簽名signkey,校驗簽名函數+字符串轉化函數objtostring:    數組

function signrequest
(data) {
data = objKeySort(data);//請求參數排序
var staticstr = '';
var timestr = parseInt((new Date()).getTime() / 1000);
var oncekey = parseInt(Math.random() * (100000 - 1000 + 1) + 1000, 10);
var wxsmall = md5(oncekey);
console.log("wxsmall:" + wxsmall);
var hash = md5(md5(wxsmall + '' + oncekey));
console.log("hash:" + hash);
var datastr = objtostring(data);
console.log("hash+datastr:" + hash + datastr);
var sign = md5(hash + datastr);
return { "timestr": timestr, "oncekey": oncekey, "wxsmall": wxsmall, "signkey": sign };
}
 
function objtostring(data) {//Object to String
var str = '';
for (var k in data) {
str += k + '=' + encodeURI(data[k]) + '&';
}
if (str) {
str = str.substring(str, str.length - 1);
}
return str;
}
3.數據解密規則:
  • 對簽名經過後返回的data加密串signdata進行base64解碼,獲得Base64後的串,Base64解碼函數decode=>
  • function  decode(input) {
    var output = "";
    var chr1, chr2, chr3;
    var enc1, enc2, enc3, enc4;
    var i = 0;
    input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
    while (i < input.length) {
    enc1 = _keyStr.indexOf(input.charAt(i++));
    enc2 = _keyStr.indexOf(input.charAt(i++));
    enc3 = _keyStr.indexOf(input.charAt(i++));
    enc4 = _keyStr.indexOf(input.charAt(i++));
    chr1 = (enc1 << 2) | (enc2 >> 4);
    chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
    chr3 = ((enc3 & 3) << 6) | enc4;
    output = output + String.fromCharCode(chr1);
    if (enc3 != 64) {
    output = output + String.fromCharCode(chr2);
    }
    if (enc4 != 64) {
    output = output + String.fromCharCode(chr3);
    }
    }
    output = _utf8_decode(output);
    return output;
    }
    // private method for UTF-8 decoding
    var _utf8_decode = function (utftext) {
    var string = "";
    var i = 0;
    var c = 0,
    c1 = 0,
    c2 = 0,
    c3 = 0;
    while (i < utftext.length) {
    c = utftext.charCodeAt(i);
    if (c < 128) {
    string += String.fromCharCode(c);
    i++;
    } else if ((c > 191) && (c < 224)) {
    c2 = utftext.charCodeAt(i + 1);
    string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
    i += 2;
    } else {
    c2 = utftext.charCodeAt(i + 1);
    c3 = utftext.charCodeAt(i + 2);
    string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
    i += 3;
    }
    }
    return string;
    }
  • 截取BASE64串string長度-4後進行MD5,並對MD5後的字符串截取長度15的串,將該串與BASE64串string長度-4後的串進行異或運算獲得解密後的data字符串=>
  • function responseencode(data, apiSignModel) {//data => encode string
    var isencode = 0;
    isencode = apiSignModel;

    if (!isencode) {
    return data;
    }
    console.log("---callback-----data---encode--->", data);
    data = base64.decode(data);//encodeString

    var rand = data.substring(data.length - 4);
    var md = md5(rand);
    var p = md.substring(0, 16);
    console.log("data " + data);
    console.log("rand " + rand);
    data = data.substring(0, data.length - 4);
    data = strox(data, p);
    console.log("p " + p);
    return data;
    }

 其中apiSignModel就是responseHeader返回的API-SIGN-MODAL,客戶端能夠根據該返回參數決定是否對返回的數據串 解密,異或運算是爲了獲得通過一次異或運算以前的初始加密串,字符串在通過兩次異或運算會獲得原始的數據,參考https://www.lijinma.com/blog/2014/05/29/amazing-xor/,異或勻速算實現函數=>微信

function strox(str, orstr) {
var result = [];
var len = orstr.length;

for (var i = 0; i < str.length; i++) {
var item = str[i];
var strcode = parseInt(item.charCodeAt().toString(10));
var orcode = parseInt(orstr[i % len].charCodeAt().toString(10));
var rescode = strcode ^ orcode;
var binaryStr = String.fromCharCode(rescode);
result.push(binaryStr);
}
return result.join("");
}
簡單來講,異或運算函數是將兩個參數1和2相加進行異或獲得3,再次異或運算後可將3和1進行異或就能夠得出異或前的數字2.總體代碼封裝一下就是這樣:
import md5 from './md5-support.js';
var Base64 = function () {

// private property
var _keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";

// public method for decoding
this.decode = function (input) {
var output = "";
var chr1, chr2, chr3;
var enc1, enc2, enc3, enc4;
var i = 0;
input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
while (i < input.length) {
enc1 = _keyStr.indexOf(input.charAt(i++));
enc2 = _keyStr.indexOf(input.charAt(i++));
enc3 = _keyStr.indexOf(input.charAt(i++));
enc4 = _keyStr.indexOf(input.charAt(i++));
chr1 = (enc1 << 2) | (enc2 >> 4);
chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
chr3 = ((enc3 & 3) << 6) | enc4;
output = output + String.fromCharCode(chr1);
if (enc3 != 64) {
output = output + String.fromCharCode(chr2);
}
if (enc4 != 64) {
output = output + String.fromCharCode(chr3);
}
}
output = _utf8_decode(output);
return output;
}

// private method for UTF-8 decoding
var _utf8_decode = function (utftext) {
var string = "";
var i = 0;
var c = 0,
c1 = 0,
c2 = 0,
c3 = 0;
while (i < utftext.length) {
c = utftext.charCodeAt(i);
if (c < 128) {
string += String.fromCharCode(c);
i++;
} else if ((c > 191) && (c < 224)) {
c2 = utftext.charCodeAt(i + 1);
string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
i += 2;
} else {
c2 = utftext.charCodeAt(i + 1);
c3 = utftext.charCodeAt(i + 2);
string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
i += 3;
}
}
return string;
}
}

var Apisecure = function () {
var base64 = new Base64();
function strox(str, orstr) {
var result = [];
var len = orstr.length;

for (var i = 0; i < str.length; i++) {
var item = str[i];
var strcode = parseInt(item.charCodeAt().toString(10));
var orcode = parseInt(orstr[i % len].charCodeAt().toString(10));
var rescode = strcode ^ orcode;
var binaryStr = String.fromCharCode(rescode);
result.push(binaryStr);
}
return result.join("");
}

function objtostring(data) {
var str = '';
for (var k in data) {
str += k + '=' + encodeURI(data[k]) + '&';
}
if (str) {
str = str.substring(str, str.length - 1);
}
return str;
}


function objKeySort(obj) {//排序的函數
var newkey = Object.keys(obj).sort();
//先用Object內置類的keys方法獲取要排序對象的屬性名,再利用Array原型上的sort方法對獲取的屬性名進行排序,newkey是一個數組
var newObj = {};//建立一個新的對象,用於存放排好序的鍵值對
for (var i = 0; i < newkey.length; i++) {//遍歷newkey數組
newObj[newkey[i]] = obj[newkey[i]];//向新建立的對象中按照排好的順序依次增長鍵值對
}
return newObj;//返回排好序的新對象
}


this.signrequest = function (data) {
data = objKeySort(data);//請求參數排序
var staticstr = '';
var timestr = parseInt((new Date()).getTime() / 1000);
var oncekey = parseInt(Math.random() * (100000 - 1000 + 1) + 1000, 10);
var wxsmall = md5(oncekey);
console.log("wxsmall:" + wxsmall);
var hash = md5(md5(wxsmall + '' + oncekey));
console.log("hash:" + hash);
var datastr = objtostring(data);
console.log("hash+datastr:" + hash + datastr);
var sign = md5(hash + datastr);
return { "timestr": timestr, "oncekey": oncekey, "wxsmall": wxsmall, "signkey": sign };
}

this.responseencode = function (data, apiSignModel) {//data => encode string
var isencode = 0;
isencode = apiSignModel;

if (!isencode) {
return data;
}
console.log("---callback-----data---encode--->", data);
data = base64.decode(data);//encodeString

var rand = data.substring(data.length - 4);
var md = md5(rand);
var p = md.substring(0, 16);
console.log("data " + data);
console.log("rand " + rand);
data = data.substring(0, data.length - 4);
data = strox(data, p);
console.log("p " + p);
return data;
}

}
module.exports = {
Base64,
Apisecure
}
最後附上小程序內封裝的微信請求調用方法=>
相關文章
相關標籤/搜索