053-请求头Hash:gov土地市场网

案例地址:土地市场网

郑重声明:本文只做学习研究分享,若有人用文章技术做出不法行为与本人无关,如有侵权联系作者立即删除

找加密参数

打开供应计划页面,F12 抓包,数据是这个接口给的:

POST https://api.landchina.com/tGyjh/plan/list

请求头里除了正常的 UA、Referer,还多了一个 Hash,值是 64 个十六进制字符。64 位正好是 SHA256 的长度,先记下这个直觉------目标就是这个 Hash 怎么来的。

定位加密位置

给这个接口下个断点(Sources 里勾 XHR/Fetch 断点,填 plan/list),刷新页面,请求会停在"发出去之前"。看调用栈:

复制代码
0. <anonymous>   chunk-vendors...js
1. xhr           chunk-vendors...js
2. er            chunk-vendors...js

栈顶全是 chunk-vendors 里的东西,也就是 axios 自己发请求的那段代码。这说明 Hash 不是在这一步算的,而是在请求真正发出之前,就被 axios 的"请求拦截器"塞进 headers 了。所以别在栈里硬跟,直接去拦截器找。

拦截器既然跟 UA 有关,那它一定会读 userAgent。全局搜 userAgent,在 app.js 里命中这段:

复制代码
let o = n(2966), a = e.url.split("/");
console.log(navigator.userAgent + (new Date).getDate() + a[a.length - 1]);
t["Hash"] = o(navigator.userAgent + (new Date).getDate() + a[a.length - 1]);

翻译成人话:

  • a = e.url.split("/") 把接口地址按 / 切开,a[a.length-1] 就是最后一段,这里是 list;
  • (new Date).getDate() 是今天的"几号"(1~31,没有前导零);
  • 把 UA + 几号 + list 三段拼一起当"种子",交给 o(n(2966) 就是 crypto-js 里的 SHA256)算一下,结果塞进请求头 Hash。

顺便说一句,开发者忘了删那句 console.log(种子)------等于把答案直接打印给你看。这种漏网细节遇到了别客气,顺着它验证最省事。

复现加密逻辑

先别信它一面之词,本地按这个规则拼种子算一遍,跟抓包看到的 Hash 对一下:

复制代码
import hashlib
UA = "Mozilla/5.0 ... Chrome/155.0.0.0 Safari/537.36"
seed = UA + "21" + "list"          # 今天 21 号
print(hashlib.sha256(seed.encode()).hexdigest())
# 182aafdba960ff4188487bf65b633f110baef14adf9dcab07249e17b9c2c6dc7

跟请求头里的 Hash 一毛一样,标准 SHA256,确认无误。完整复现:

复制代码
import hashlib
from datetime import datetime
import requests

UA = ("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 "
      "(KHTML, like Gecko) Chrome/155.0.0.0 Safari/537.36")
API_URL = "https://api.landchina.com/tGyjh/plan/list"

def build_hash(url):
    # UA + 当日几号 + URL末段 → SHA256
    seed = UA + str(datetime.now().day) + url.split("/")[-1]
    return hashlib.sha256(seed.encode("utf-8")).hexdigest()

def fetch_plan_list(page_num=1, page_size=10):
    headers = {"Hash": build_hash(API_URL),
               "Origin": "https://www.landchina.com",
               "Referer": "https://www.landchina.com/",
               "User-Agent": UA}
    payload = {"pageNum": page_num, "pageSize": page_size, "startDate": "", "endDate": ""}
    r = requests.post(API_URL, headers=headers, json=payload, timeout=10)
    r.raise_for_status()
    return r.json()

if __name__ == '__main__':
    data = fetch_plan_list(page_num=2, page_size=10)
    body = data.get("data") or {}
    print("code:", data.get("code"), "| msg:", data.get("msg"))
    print("总数:", body.get("total"), "| 本页:", len(body.get("list") or []))
    for item in (body.get("list") or [])[:3]:
        print(" -", item.get("biaoti"), "|", item.get("xzqFullName"))

结果

本机刚跑的:

复制代码
code: 200 | msg: 操作成功
总数: 1414 | 本页: 10
 - 法库县2026年度国有建设用地供应计划 | 辽宁省沈阳市法库县
 - 沈阳市2026年度国有建设用地供应计划 | 辽宁省沈阳市本级
 - 康平县2026年度国有建设用地供应计划 | 辽宁省沈阳市康平县

踩坑

  • UA 必须和你请求头里真正发出去的那串一字不差,差一个字符 Hash 就对不上;
  • 日期只取"几号"(1~31),不是完整日期,而且用的是电脑本地时间,过了零点或换了时区会变;
  • 最后一段是 list,换别的接口时把新地址传进 build_hash 就行,规则不用改。

小结

这篇不难,就是个"请求头藏了个 SHA256"。套路记住两点:看到请求头里莫名多出一串固定长度的十六进制,先猜 hash(UA + 时间 + 接口名) 这种拼接;跟栈发现栈顶都是 axios 自己的代码时,别硬跟,去请求拦截器里找。如有问题请及时提出,加油加油。

相关推荐
嫂子的姐夫3 小时前
052-滑块验证码:丰巢登录
爬虫·js逆向·滑块验证码·aes加密
深蓝电商API1 个月前
大语言模型能否自动完成 JS 逆向?
爬虫·js逆向
EXI-小洲2 个月前
Web Spider 某渣渣企业平台 表单参数逆向 Webpack
python·webpack·js逆向·spider
Amo Xiang4 个月前
数位观察城市数据查询 —— AES/ECB/PKCS7 响应解密与数据采集
js逆向·python爬虫·爬虫逆向·aes解密·响应解密·数位观察
冰履踏青云4 个月前
东方航空 refer__1036逆向复盘
js逆向·东航·refer__1036
如烟花的信页4 个月前
外贸*登录逆向分析
javascript·爬虫·python·js逆向
冰履踏青云4 个月前
从 202 到 200:一次 aws-waf-token 纯 Python 还原实录
js逆向·aws-waf-token
Amo Xiang4 个月前
SpiderDemo 第5题:OB混淆实战 —— 反调试绕过与 signature 签名还原
python·js逆向·爬虫逆向·反调试·spiderdemo·ob混淆
冰履踏青云4 个月前
宏翼平台登录参数逆向
js逆向·宏翼平台登录