尝试写一个基于网页版的python-cli自用客户端。

登录偷懒使用selenium搞定,然而发现无论post什么返回json提示鉴权失败

经过排查发现是一个名为CMS-SIGN的header起到验证作用

CMS-SIGN:1597186314153,hhixIlynVVT6FCaD,2B6714788235D616B01349BA234ADBFA

第一项明显是Unix时间戳,第二项是16位随机字母数字串。

第三项就是需要根据post内容,时间戳和字符串生成的密码

通过浏览器逐步运行发现CMS-SIGN内容是由一个名为getSign的function生成的。

源代码如下

参数:

e:POST请求的内容,整个json payload

t:懒得分析所以不明,一般直接把None扔进去就行

n:13位Unix时间戳,比如:"1597114116005"

a:16个随机大写字母数字组合,比如“9iWRRehE60XOGEMl”

返回内容:用于CMS-SIGN最后一项的字符串

getSign: function(e, t, n, a) {
                var r = "";
                function i(e) {
                    var t = [];
                    for (var n in e) if (e[n] || 0 === e[n] || "0" === e[n] || !1 === e[n]) if (e[n] instanceof Object && !(e[n] instanceof Array)) {
                        if (e[n] !== {} && 0 !== Object.keys(e[n]).length) {
                            var a = "{".concat(i(e[n]), "}"),
                            o = n + "=" + a;
                            t.push(o)
                        }
                    } else if (e[n] instanceof Array) {
                        var r = e[n];
                        if (0 !== r.length) {
                            var s = "";
                            for (var u in r) r[u] instanceof Object ? s = "".concat(s, "{").concat(i(r[u]), "}") : s += r[u],
                            u < r.length - 1 && (s += ",");
                            var c = n + "=" + s;
                            t.push(c)
                        }
                    } else {
                        if ("string" === typeof e[n] && "" === e[n].trim()) continue;
                        var A = n + "=" + e[n];
                        t.push(A)
                    }
                    return 0 !== t.length ? (t = t.sort(), t.join("&")) : ""
                }
                var s = Object.assign({},
                t, e),
                u = i(s);
                return r = u + (u ? "&": "") + "key=" + o()(n + ":" + a),
                r = o()(r).toUpperCase(),
                r
				}

很明显代码经过混淆读起来非常头痛,于是打算python上使用execjs直接运行

然而这段代码缺少了 o()这个function的声明,运行起来肯定会报错

又经过逐步运行发现o()其实只是一个md5码生成。

用node.js 的md5-node代替

于是经过修改后的代码成为

function getSign(e, t, n, a) {
    var r = "";
    var md5=require('md5-node');
    function i(e) {
        var t = [];
        for (var n in e) if (e[n] || 0 === e[n] || "0" === e[n] || !1 === e[n]) if (e[n] instanceof Object && !(e[n] instanceof Array)) {
            if (e[n] !== {} && 0 !== Object.keys(e[n]).length) {
                var a = "{".concat(i(e[n]), "}"),
                    o = n + "=" + a;
                t.push(o)
            }
        } else if (e[n] instanceof Array) {
            var r = e[n];
            if (0 !== r.length) {
                var s = "";
                for (var u in r) r[u] instanceof Object ? s = "".concat(s, "{").concat(i(r[u]), "}") : s += r[u],
                u < r.length - 1 && (s += ",");
                var c = n + "=" + s;
                t.push(c)
            }
        } else {
            if ("string" === typeof e[n] && "" === e[n].trim()) continue;
            var A = n + "=" + e[n];
            t.push(A)
        }
        return 0 !== t.length ? (t = t.sort(), t.join("&")) : ""
    }
    var s = Object.assign({},
        t, e),
        u = i(s);
    return r = u + (u ? "&": "") + "key=" + md5(n + ":" + a),
        r = md5(r)
        r = r.toUpperCase(),r

}
跑了一下得出结果没问题

4 Comments

  • 你好,最近想做和彩云的自动转发功能,看了你们的文章,很受鼓舞,但签名算法怎么也通不过,不知道是和彩云改变算法了,还是我的算法有问题。

    麻烦您核实一下:
    1、和彩云的签名算法未改变。
    2、请提供一个,加密过程的中间数据及加密结果值,以便检查我的算法是否正确。

    谢谢!!!

  • 终于解决了!

    和彩云没有更新算法,你我在md5加密过程中出了点问题,

    第一次加密 md5(n + “:” + a),我把结果输入为大写格式,

    所以导致之前一致鉴权失败。

    现通过fillder替换 js文件,输入加密过程的值,发现了问题所在。

    感谢楼主提供的思路,开始的时候完全没有方向,看了你的文章后,就简单多了。

  • 能否实现和彩云的自动上传?

    现在卡在本地文件的选择上,没有找到相关的接口

    1. 这个我不太清楚,我发现网页端接口上传最大只能2G后就没继续弄了。