某公开数据简单逆向

政府网站 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 中,无需注册即可使用。


免责声明

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

相关推荐
leisoo80974 小时前
100GBA股股票数据怎么存ClickHouseRedisMySQLJSON完整对比
大数据·linux·服务器·开发语言·python
WangYan20224 小时前
基于XGBoost与AI的生态—地学多源数据建模:植被与土地利用识别、土壤碳氮空间预测、生物多样性驱动机制、土壤微生物功能预测、生态退化与风险识别
python·机器学习·xgboost
金銀銅鐵7 小时前
[Python] 借助 turtle 逐字展示唐诗《金缕衣》
python
Python大数据分析@9 小时前
使用大模型MCP采集数据,爬虫已经无门槛
python·网络爬虫
quantdash_cc9 小时前
告别自建 Requests/BS4 网页爬虫:基于 QuantDash 搭建零维保的高性能量化行情流水线
开发语言·爬虫·python·pandas·量化·quantdash
65岁退休Coder9 小时前
LangChain v1.3.4 笔记 - 07 补充:链式调用 LCEL
后端·python·langchain
卷无止境10 小时前
FastAPI 部署在 Nginx 后面到底该怎么配
后端·python
半亩码田10 小时前
C#转Python第3.1篇:Python 的 class 没有访问修饰符?面向对象的另一条路
开发语言·python·c#
Wzx19801210 小时前
python沙箱和docker沙箱你选对了吗?
开发语言·python·docker
Python私教10 小时前
签名 URL 刷新导致审批失效?别急着删掉所有 query
python·安全