您现在的位置是:首页 > 技术人生 > 后端技术后端技术

js解密之获取中高风险地区接口(一)

高晓波2023-02-13【后端技术】人已围观

简介最近部门做了一个疫情信息填报的小程序,里面涉及到行程码途经地及来宁地区是否为中高风险的智能判断,加上数据治理项目组那边也需要获取中高风险地区数据,所以开始寻找全国中高风险地区发布的来源。

一、前言

最近部门做了一个疫情信息填报的小程序,里面涉及到行程码途经地及来宁地区是否为中高风险的智能判断,加上数据治理项目组那边也需要获取中高风险地区数据,所以开始寻找全国中高风险地区发布的来源。

二、数据来源

通过网上搜索后发现,中高风险地区的发布有以下来源:

  1. 本地宝,http://m.bj.bendibao.com/news/gelizhengce/fengxianmingdan.php
  2. 小程序:国务院客户端

本地宝采用的是服务端渲染,想拿到中高风险地区要解析dom,比较麻烦。
国务院客户端无疑是最权威、最及时的发布方,猜测其他地方的风险地区信息来源都是这儿。但是有个比较棘手的问题,国务院客户端小程序默认是微信登陆,无法通过接口调用的方式进行模拟;加上小田、小鑫的测试发现,cookie每天0点会自动失效,意味着每天都要人工进行登陆拿取cookie,长期来看无疑是个麻烦的工作,如果哪天忘了更新cookie,会造成信息更新不及时的后果。

最终,通过苦苦寻找发现了国家卫健委web发布端http://bmfw.www.gov.cn/yqfxdjcx/risk.html,这为风险地区的自动获取带来了新的途径。

三、接口难点

通过浏览器调试模式,查看接口参数返回值等情况发现,参数中存在时间戳和加密签名。


 

那么,就存在以下问题:

  1. 1.如果传参的时间戳与当前时间距离超过180秒会报错,意味着我们不能拿固定参数进行接口调用
  2. 2.时间戳参数参与签名参数的生成,意味着我们光改时间戳为当前时间戳是没有用的,时间戳变了,签名参数校验会不通过
  3. 3.签名参数的生成方式。




 

四、解决方案

1. 模拟操作浏览器

如:开源的Selenium,或是直接通过api操作chrome或Chromium。此种方式的好处是简单粗暴,缺点是比较耗费资源,并且本质上是浏览器真实的访问目标站点,需要加载运行各种资源,故效率较低。一般对于深度加密防爬的站点实在没有办法才采取这样的方式,本篇暂不讨论。

2. js解密

此种方式优点是直接调用api,效率自然是最高,另外大部分接口返回数据为json,数据解析也是最为方便;缺点是对技术要求较高且需要花费时间进行js解密。本篇我们主要讨论此方式。

五、签名生成方式分析

想要成功的获取到数据,必须弄清楚参数中的signatureHeader生成方式,以及其他一些关键参数的来源,如:参数中的key、appId、paasHeader、nonceHeader。
当然,部分参数可以写死,但如果后面发布方进行了参数更新,那么接口调用也随之会失效。所以以上参数,我们都尽量采用动态获取的方式。

1. 搜索关键字: signatureHeader

我们以参数中的signatureHeader作为关键字,在js中进行搜索,搜索结果如下:


 

存在signatureHeader关键字的js有两处,这两处都在risk.dc7936e2.js中,从Respons中我们看到,这是一段经过压缩加密处理的js。

2. 对risk.js进行格式化

我们利用chrome调试工具对js代码格式化,再将格式化后的js代码粘贴到代码编辑器中,方便我们阅读分析




 

3. js代码分析

首先我们还是找到signatureHeader关键字处。
 

function v(e) {
    if (!e.commonParams)
        return e;
    var t = c.value;
    return e.data = e.data || {},
        Object.assign(e.data, {
            appId: "NcApplication",
            paasHeader: o,
            timestampHeader: t,
            nonceHeader: s,
            signatureHeader: CryptoJS.SHA256(t + r + s + t).toString(CryptoJS.enc.Hex).toUpperCase()
        }),
        e
}
 

上述代码我们解读一下:接口参数appId值为NcApplication,参数paasHeader值为变量o,参数timestampHeader值为变量t,从参数名和值上猜测为时间戳,参数nonceHeader值为变量s,参数signatureHeader的生成方式是变量t+r+s+t拼接后进行sha256加密。

参数追踪

上述代码我们看到var t = c.value;, 再追踪参数c:
 

        var a = n("bc3a"),
            i = n.n(a),
            r = (n("b680"),n("25f0"),"23y0ufFl5YxIyGrI8hWRUZmKkvtSjLQA"),
            s = "123456789abcdefg",
            o = "zdww",
            c = {
                value: 0
            };
 

发现c.value的默认值是0,猜测一定有其他地方更改了这个值。
另外,从此段代码中我们发现了变量s(对应接口参数nonceHeader)的值为123456789abcdefg;变量r前面两个n("b680")和n("25f0")是干扰项,真正的值为23y0ufFl5YxIyGrI8hWRUZmKkvtSjLQA;变量o(对应接口参数paasHeader)的值为zdww

继续追踪变量c发现:

        function d(e) {
            return c.value = (Date.now() / 1e3).toFixed(),
                e
        }

原来c.value是个10位时间戳,所以,变量t和我们猜测的一样,为时间戳。

参数key查找

我们再看一下接口发送的请求参数:
 

{
	"key": "3C502C97ABDA40D0A60FBEE50FAAD1DA",
	"appId": "NcApplication",
	"paasHeader": "zdww",
	"timestampHeader": "1658923498",
	"nonceHeader": "123456789abcdefg",
	"signatureHeader": "5590D43894BA76A541AB0403705BE08BF5B1AB17E100FC325631A25A143E8D62"
}
其中的appId,paasHeader,timestampHeader,nonceHeader我们都已经知道从何而来,signatureHeader也知道是如何产生的:sha256(t+r+s+t),拿浏览器的参数进行反向验证:
t的值为:1658923498
r的值为:23y0ufFl5YxIyGrI8hWRUZmKkvtSjLQA
s的值为:123456789abcdefg
t+r+s+t值为:165892349823y0ufFl5YxIyGrI8hWRUZmKkvtSjLQA123456789abcdefg1658923498
进行sha256加密后为:5590d43894ba76a541ab0403705be08bf5b1ab17e100fc325631a25a143e8d62,计算得出的值与我们从浏览器中得到的参数signatureHeader一致,验证了我们的分析没有错。
那么,现在还剩下参数key。我们在js代码中搜索参数key的值:3C502C97ABDA40D0A60FBEE50FAAD1DA:
        var j = "243D215B2CA449ECABF1E6C93B7D973C",
            x = "2CA32596474B4077834CCC191D351839",
            O = "3C502C97ABDA40D0A60FBEE50FAAD1DA";
key的值为变量O的值,继续追踪:
        function k() {
            return _({
                data: {
                    key: O
                }
            }).then((function(e) {
                return e.data
            }))
        }

k函数中,将变量O的值赋给了key。因为上面定义了3个变量j、x、O,而赋值的是O,猜测后面有可能会换成其他的。

至此,接口中所有参数的值都已经搞定。

 

Tags:js解密

很赞哦! ()

文章评论