机场云商sign算法分析学习笔记

最近机场云商开门了,手动挡怎么也下不了车,那就直接上柯基

抓包发现请求头有sign、nonceStr参数且每次请求都不一样

POST /api/consumer/order/addOrder HTTP/1.1
Host: www.gza-e.com
Connection: keep-alive
Content-Length: 122
sign: 51538ca78aa0360efc7234c12f157dd0
timestamp: 1667361180
accessToken: ODg5NjU0NzU4MTc5MDc4MTQ0OjE6ZWQ2NDNmYjc1MzgxNDk4Y2IxNTI0M2QzYWRiZDQ2NjA=
content-type: application/json
nonceStr: d7f0aa20caf546d08c3f0289486a62dc
Accept-Encoding: gzip,compress,br,deflate
User-Agent: Mozilla/5.0 (iPhone; CPU iPhone OS 16_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 MicroMessenger/8.0.29(0x18001d34) NetType/4G Language/en
Referer: https://servicewechat.com/wx88c590140de89f92/203/page-frame.html

{"orgId":"817425775685795840","proProType1":3,"orderDetailList":[{"ostId":"","proId":"1003627106498117633","quantity":1}]}

话不多说直接反编译小程序在源码中搜索某sign发现一个函数01bc4fa4f9ec443d8e8394ed77f9a4fe.png

 跟踪s()函数发现签名算法就在其中

function s(o, n, s, r, i) {
    for (var d = "", c = 0, u = Object.keys(o).sort(); c < u.length; c++) {
        var l = u[c], f = o[l];
        if ("object" === e(f) && null !== f) {
            var g = JSON.stringify(o[l]);
            d += l + "=" + (g = g.split("").sort().join("")) + "&";
        } else 0 === f || f ? d += l + "=" + o[l] + "&" : (o[l] = "", d += l + "=&");
    }
    return d += "url=" + n + "&", d += s ? "accessToken=" + s + "&" : "", d += "timestamp=" + r + "&", 
    d += "nonceStr=" + i + "&", d += "key=" + t.default.PLAM_KEY, a.md5Encrypt(d);
}

 进过一系列分析发现签名函数的几个参数分别为post所提交的json数据,请求的url,accessToken,timestamp和nonceStr这几个参数,至于PLAM_KEY则为一个固定值,接下来就是找到nonceStr的算法了

跟踪源码发现:

a56b510e152f44b7a17532a05ce661e5.png

nonceStr这个参数是随机的,且"xxxxxxxxxxxx4xxxyxxxxxxxxxxxxxxx"中的“4”作为验证,timestamp则为时间戳,接下来就简单了,直接改写签名算法

java版

package com.hotel.hotelmaster.test;

import com.alibaba.fastjson.JSONObject;
import org.apache.commons.codec.digest.DigestUtils;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.UUID;

/**
 * @author yangchen
 */
public class SignUtils {
    public static final String HOST = "https://www.gza-e.com/api";
    public static final String PLAM_KEY = "ca235e27dcf94107889b9ad00ceebd48";

    /**
     * 获取nonceStr
     *
     * @return
     */
    public static String getNonceStr() {
        return UUID.randomUUID().toString().replace("-", "");
    }

    /**
     * 获取时间戳
     *
     * @return
     */
    public static Long getTimestamp() {
        return System.currentTimeMillis() / 1000;
    }

    /**
     * 判断是否为json对象
     *
     * @param str
     */
    public static boolean getJsonType(String str) {
        boolean result = false;
        if (str != null) {
            str = str.trim();
            if (str.startsWith("{") && str.endsWith("}")) {
                result = true;
            } else if (str.startsWith("[") && str.endsWith("]")) {
                result = true;
            }
        }
        return result;
    }

    /**
     * 签名接口
     *
     * @param postData
     * @param url
     * @param accessToken
     * @param timestamp
     * @param nonceStr
     */
    public static String signature(JSONObject postData, String url, String accessToken, long timestamp, String nonceStr) {
        List<String> keyList = new ArrayList<>();
        String d = "";
        for (String key : postData.keySet()) {
            keyList.add(key);
        }
        Collections.sort(keyList);
        for (int i = 0; i < keyList.size(); i++) {
            String key = keyList.get(i);
            String value = postData.get(key).toString();
            if (getJsonType(value) && value != null) {
                List<String> valueList = new ArrayList<>();
                for (int j = 0; j < value.length(); j++) {
                    valueList.add(String.valueOf(value.charAt(j)));
                }
                Collections.sort(valueList);
                d += key + "=";
                for (int k = 0; k < valueList.size(); k++) {
                    d += valueList.get(k);
                }
                d += "&";
            } else {
                d += key + "=" + value + "&";
            }
        }
        d += "url=" + url.replace(HOST, "") + "&";
        d += "accessToken=" + accessToken + "&";
        d += "timestamp=" + timestamp + "&";
        d += "nonceStr=" + nonceStr + "&";
        d += "key=" + PLAM_KEY;
        return DigestUtils.md5Hex(d);
    }

    public static void main(String[] args) {
        String url="https://www.gza-e.com/api/consumer/order/addOrder";
        String accessToken = "ODg5NjU0NzU4MTc5MDc4MTQ0OjE6ZWQ2NDNmYjc1MzgxNDk4Y2IxNTI0M2QzYWRiZDQ2NjA=";
       String nonceStr= "d7f0aa20caf546d08c3f0289486a62dc";
       JSONObject postData=JSONObject.parseObject("{\"orgId\":\"817425775685795840\",\"proProType1\":3,\"orderDetailList\":[{\"ostId\":\"\",\"proId\":\"1003627106498117633\",\"quantity\":1}]}");
       long timestamp= 1667361180;
       String sign=signature(postData,url,accessToken,timestamp,nonceStr);
        System.out.println(sign);
    }

python版

def signature(postData, url, accessToken, timestamp, nonceStr):
    PLAM_KEY = "ca235e27dcf94107889b9ad00ceebd48"
    host = "https://www.gza-e.com/api"
    url = url.replace(host, "")
    keys = sorted(postData.keys())
    d = ""
    for key in keys:
        if isinstance(postData[key], list) or isinstance(postData[key], dict) or postData[key] is None:
            g = str(json.dumps(postData[key])).replace(" ", "")
            ls = []
            for i in range(len(g)):
                ls.append(g[i])
            ls.sort()
            d += key + "="

            for s in ls:
                d += s
            d += "&"

        else:
            d += key + "=" + str(postData[key]) + "&"
    d += "url=" + url + "&"
    d += "accessToken=" + accessToken + "&"
    d += "timestamp=" + str(timestamp) + "&"
    d += "nonceStr=" + nonceStr + "&"
    d += "key=" + PLAM_KEY

    return hashlib.md5(d.encode("utf8")).hexdigest()

用刚刚抓包的结果验证一下签名结果相同

aa1f82a08d244532a1785fbc0c57bb75.png

再重新发起一个新的请求看看是否能够请求成功

b1e49519d13b4ddc8c377c5781372d0c.png

大功告成,完美!

仅供学习参考!!!

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 12
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值