某公开数据简单逆向

政府网站 API 逆向分析实战:噪声数据采集

一句话总结

从目标网站前端 JS 中提取硬编码的第三方 API 地址和认证凭据,直接调用外部数据平台接口获取结构化数据。


逆向流程

步骤 1:访问目标网站

页面正常返回 200,HTML 中包含多个 <script> 标签。

步骤 2:定位核心 JS 文件

在 HTML 中找到关键脚本引用:

html 复制代码
<script src="../../images/zsjs*_sthjt_jkjs.js"></script>

步骤 3:下载并分析 JS

从目标网站下载对应的 JS 文件,发现是未混淆的明文代码

关键发现 1:API 配置(硬编码)

javascript 复制代码
var API_CONFIG = {
  baseUrl: "https://*.jlzslw.com:50003",   // 第三方数据平台
  username: "InterfaceCall",
  secretKey: "******",                      // 硬编码密钥
  sysCode: "NOISE"
};

关键发现 2:3 个 API 接口

搜索 JS 中的 ajax / Get 关键词,找到 3 个接口路径:

接口路径 功能
/GetExternalApiToken 获取 Token
/GetBSDStationListAsync 获取站点列表
/GetDATStationHourDisplayListAsync 获取噪声小时数据

步骤 4:分析 getToken 函数

javascript 复制代码
function getToken() {
  $.ajax({
    type: "GET",
    url: API_CONFIG.baseUrl + "/api/noiseproduct/AirCityBaseCommon/GetExternalApiToken",
    data: { UserName: API_CONFIG.username, SecretKey: API_CONFIG.secretKey },
    dataType: "json",
    success: function (response) {
      if (response && response.result) {
        RESULT_DATA.token = response.result;

关键点

  • 请求方式:GET
  • 参数名大小写敏感:UserNameSecretKey(首字母大写)
  • Token 位置:response.result

步骤 5:分析站点列表接口

javascript 复制代码
$.ajax({
  type: "GET",
  url: API_CONFIG.baseUrl + "/api/noiseproduct/AirCityProductBase/GetBSDStationListAsync",
  headers: { SysCode: API_CONFIG.sysCode, Authorization: "Bearer " + RESULT_DATA.token },

关键点

  • 请求方式:GET
  • 必须携带 Headers:SysCodeAuthorization: Bearer {token}

步骤 6:分析噪声数据接口

javascript 复制代码
$.ajax({
  type: "GET",
  url: API_CONFIG.baseUrl + "/api/noiseproduct/airdata/DATStationHour/GetDATStationHourDisplayListAsync",
  headers: { SysCode: API_CONFIG.sysCode, Authorization: "Bearer " + RESULT_DATA.token },
  data: $.param({
    codes: cityData.map(function (item) { return item.stationCode; }),
    dataType: 0,
    timePoint: dayjs().format("YYYY-MM-DD HH:00:00")
  }, true),

关键点

  • codes:站点编码列表
  • dataType: 0:固定值
  • timePoint必需字段 ,格式 YYYY-MM-DD HH:00:00

步骤 7:Python 验证

python 复制代码
import requests

session = requests.Session()
session.verify = False

# 1. 获取 Token
token = session.get(
    API_BASE + "/api/noiseproduct/AirCityBaseCommon/GetExternalApiToken",
    params={"UserName": "InterfaceCall", "SecretKey": "******"}
).json()["result"]

# 2. 获取站点列表
stations = session.get(
    API_BASE + "/api/noiseproduct/AirCityProductBase/GetBSDStationListAsync",
    headers={"SysCode": "NOISE", "Authorization": f"Bearer {token}"}
).json()["result"]

# 3. 获取噪声数据
data = session.get(
    API_BASE + "/api/noiseproduct/airdata/DATStationHour/GetDATStationHourDisplayListAsync",
    headers={"SysCode": "NOISE", "Authorization": f"Bearer {token}"},
    params={"codes": "1001A", "dataType": 0, "timePoint": "2026-05-22 12:00:00"}
).json()["result"]

数据流转图

复制代码
─────────────────────────────────────────────────────────────┐
│  1. GET /GetExternalApiToken                                │
│     → Token: "a24dbae..."                                  │
─────────────────────────────────────────────────────────────┤
│  2. GET /GetBSDStationListAsync                             │
│     Headers: SysCode=NOISE, Authorization=Bearer {token}    │
│     → 154 个站点 [{stationCode:"1001A", ...}, ...]         │
├─────────────────────────────────────────────────────────────┤
│  3. GET /GetDATStationHourDisplayListAsync                  │
│     ?codes=1001A&dataType=0&timePoint=2026-05-22 12:00:00  │
│     → 噪声数据 [{code:"1001A", leq:"48.4", ...}]           │
└─────────────────────────────────────────────────────────────

API 接口详情

1. 获取 Token

项目
URL https://*.jlzslw.com:50003/api/noiseproduct/AirCityBaseCommon/GetExternalApiToken
方法 GET
参数 UserName={硬编码用户名}&SecretKey={硬编码密钥}
返回 {"success":true, "result":"a24dbae..."}

2. 获取站点列表

项目
URL https://*.jlzslw.com:50003/api/noiseproduct/AirCityProductBase/GetBSDStationListAsync
方法 GET
Headers SysCode: NOISE Authorization: Bearer {token}
返回 {"result": [{id, positionName, stationCode, cityName, ...}]}

3. 获取噪声数据

项目
URL https://*.jlzslw.com:50003/api/noiseproduct/airdata/DATStationHour/GetDATStationHourDisplayListAsync
方法 GET
Headers 同上
参数 codes={站点编码}&dataType=0&timePoint={YYYY-MM-DD HH:00:00}
返回 {"result": [{code, name, leq, l5, l10, ...}]}

噪声数据字段说明

字段 说明 示例
code 站点编码 1001A
name 站点名称 某某小区
timePoint 监测时间 2026-05-22T12:00:00
leq 等效声级 dB(A) 48.4
l5 L5 52.9
l10 L10 51.4
l50 L50 46.1
l90 L90 42.3
lMax 最大声级 64.1
temperature 温度 ℃ 25.4
humidity 湿度 % 43
windSpeed 风速 m/s 2.3
isOverStandard 是否超标 false

与高难度站点的对比

对比项 高难度站点 本案站点
逆向难度 极难(VM 字节码混淆) 简单(JS 明文)
Token 来源 动态生成(解密函数) 固定凭据调用接口
API 地址 自有系统 第三方数据平台
数据托管 自有 托管至第三方平台

认证凭据(已脱敏)

复制代码
baseUrl:    https://*.jlzslw.com:50003
username:   InterfaceCall
secretKey:  ******
sysCode:    NOISE

注意:这些凭据硬编码在前端 JS 中,无需注册即可使用。


免责声明

本文仅用于技术学习和研究目的,展示的是如何通过前端逆向分析理解数据接口的工作原理。实际使用时请遵守相关法律法规和网站服务条款。

相关推荐
财经资讯数据_灵砚智能27 分钟前
基于全球经济类多源新闻的NLP情感分析与数据可视化(夜间-次晨)2026年6月10日
大数据·人工智能·python·ai·信息可视化·自然语言处理·灵砚智能
namexingyun31 分钟前
拆解Fable 5三重安全护栏:模型路由、蒸馏防护与生物安全分类器的技术原理 - 微元算力(weytoken)
java·人工智能·python·安全·架构·ai编程
chenment43 分钟前
别再为每个模型单独写一套队列了:用 200 行代码封装多模态统一调用层
人工智能·python·产品
啊森要自信1 小时前
【GUI自动化测试】控件、鼠标键盘操作与多场景自动化
c语言·开发语言·python·adb·ipython
YJlio1 小时前
《Sysinternals实战指南》16.5 Ctrl2Cap 工具详解:把 Caps Lock 变成 Ctrl 的键盘改造与回退方法
linux·运维·服务器·网络·python·学习·计算机外设
某林2121 小时前
从底层硬件死锁到 QoS 通信底层的全链路复盘
python·ros2·qos
Jutick1 小时前
WebSocket 连接没断,行情却停了:如何给实时数据流加双层 watchdog?
python
石头城的小石头1 小时前
【从0到1的鼠标位置显示记录器,基于python环境pycharm下编译实施,最终打包为exe,欢迎交流】
python·目标跟踪·pycharm·计算机外设·鼠标
用户8356290780511 小时前
Python 操作 Word 修订跟踪(Track Changes)
后端·python
电商API_180079052471 小时前
Python 实现闲鱼商品列表批量采集,接口异常重试机制搭建
大数据·开发语言·数据库·爬虫·python