ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

某元航空补环境跑通航班搜索,动态 Cookie 和 black_box gpt5.6 sol (极高)

某元航空补环境跑通航班搜索,动态 Cookie 和 black_box gpt5.6 sol (极高) 前言这次目标是某元航空网站的航班搜索接口。核心不是普通参数签名而是 Cookie 里面的指纹值和Anti-Headers里的black_box。整个流程耗时 1 小时 44 分钟使用模型5.6sol极高档位成本没超过 10 块钱。我只发了两次 prompt后面基本就是让 AI 自己沿着逆向 skill 跑最后完成动态 Cookie、动态black_box和换航线搜索。一、目标与工具1.1 目标目标接口GET https://www.xxx.com/shop/api/shopping/b2c/searchflight最终要做到三件事目标结果动态生成black_box已跑通动态生成必需 Cookie已跑通更换出发地、目的地、日期后仍可搜索已跑通1.2 工具工具作用HAR 抓包确认真实请求流程Chrome DevTools定位 SDK、Cookie、Initiator自己常用的逆向 skill规范流程避免漏步骤自我提升 skill过程记录、失败复盘Python编排请求、CookieJar、CLINode.js执行原始 SDK 和最小补环境这次没有强行纯算法还原最终方案是补环境。原因也很简单短时间直接打通后续如果要做指纹置换也可以继续让 AI 帮忙做消融和替换。二、请求流程分析2.1 搜索链路初始化会话 | |-- GET /backoffice/api/system/ip | - 下发 JSESSIONID | |-- GET /member/api/busi-parameter/getBusiParam | - 下发 SESSION | |-- 本地生成 __snaker__id | |-- 网易 Core 2.28.5 生成 fp | - encodeURIComponent(fp) | - 写入 gdxidpyhxdE | |-- TrustDecision SDK 生成 black_box | -- GET /shop/api/shopping/b2c/searchflight Cookie: JSESSIONID / SESSION / __snaker__id / gdxidpyhxdE Anti-Headers: black_box 航班条件2.2 必需字段字段位置来源处理方式JSESSIONIDCookie/backoffice/api/system/iprequests.Session自动维护SESSIONCookie/member/api/busi-parameter/getBusiParamrequests.Session自动维护__snaker__idCookie前端本地值62 字符表随机 16 位gdxidpyhxdECookie网易 Core 指纹fp原始 SDK 生成后encodeURIComponentblack_boxAnti-HeadersTrustDecision SDK原始 SDK Node 最小补环境实时生成这里有个细节HAR 里最开始看到的不是所有 Cookie 都完整所以不能只靠复制浏览器请求。旧的black_box也不能复用重放会返回业务失败。三、核心逆向过程3.1 先定位black_box前端调用链大概是webpack 模块 5e6b - loadEventHandler() - p() - k() - sessionStorage.currentBlackBox - _fmOpt.sign({ path, body })_fmOpt.success会把 TrustDecision SDK 的结果写入sessionStorage.currentBlackBox搜索时再放进请求头Anti-Headers。无Anti-Headers时接口返回业务失败使用 HAR 里过期的black_box也失败。这一步可以证明它不是固定值必须实时生成。3.2 再定位gdxidpyhxdEgdxidpyhxdE来自网易 Core 2.28.5。浏览器里可以看到decodeURIComponent(cookie.gdxidpyhxdE) 请求参数 fp也就是说它不是随便拼出来的 Cookie而是 SDK 生成的浏览器指纹最后按浏览器encodeURIComponent的方式写入 CookieJar。3.3 真正的坑Node 专属指纹这次最关键的根因不是少补了某个 API而是补多了一个不该存在的环境特征。TrustDecision SDK 会采集performance.nodeTiming。这个字段浏览器里没有但 Node 环境里存在。如果它被 SDK 采到上报接口本身仍然能返回 26 位 token看起来像是成功了但拿去请求搜索接口会稳定业务失败。最后的结论是只要对 SDK 隐藏performance.nodeTiming原始 SDK 输出的black_box就能被业务接口接受。四、补环境消融测试4.1 为什么要做消融补环境最怕的是补错一个然后 AI 觉得这是正确方向继续在错误环境上堆东西。某数这类风控经常会出现这种情况补完之后返回 400AI 可能会把 400 当成“还差一个 API”然后一直往下错。我建议单独写一个消融测试 skill。目的不是让流程变复杂而是每次只改一个变量B0当前基线 B1只加一个环境补丁 A1撤回这个补丁如果加了成功、撤回失败 - 必要如果加了失败、撤回恢复 - 有害如果加了没变化、撤回也没变化 - 删除4.2 补了哪些环境点这里不展开完整补环境代码只说这次主要补了什么环境点补的内容作用window/document/navigator/location先搭一个最小浏览器全局对象让 SDK 能按浏览器逻辑初始化不会一进来就因为对象不存在中断location.hostname/href补成目标站点的页面地址SDK 会读取当前页面上下文用来判断运行环境navigator.userAgent使用 HAR 里的浏览器 UA让 SDK 和后续接口请求保持同一套浏览器特征navigator.platform补MacIntelTrustDecision 会采集平台字段缺了会影响初始化或采集结果Worker补一个最小空WorkerSDK 内部会探测或创建 worker这里只需要让流程走下去Canvas补createElement(canvas)、getContext、toDataURL、getImageData等最小接口SDK 会采集 Canvas 指纹不补会静默中断或拿不到完整指纹performance保留 Node 原生高精度时间但隐藏performance.nodeTiming浏览器没有nodeTiming这个字段暴露会导致业务校验失败XMLHttpRequest用 Nodefetch包一层 XHRTrustDecision SDK 用 XHR 上报Node 里需要给它一个可用传输Function.prototype.toString让补出来的函数看起来像 native code过一些基础的原生函数检测核心思路不是把浏览器完整搬进 Node而是 SDK 访问到哪里就补哪里。补完之后还要做反向消融把没用的东西删掉。4.3 本次消融结果变更结论去留navigator.platformSDK 初始化需要保留Canvas 最小接口SDK 采集需要保留隐藏performance.nodeTiming解决业务校验失败保留最小WorkerSDK 初始化需要保留隐藏 Node 全局对结果无影响删除webdriver/chrome/language/click对结果无影响删除预置__snaker__id再算 fp对结果无帮助删除这就是我说的“AI 在补环境这个板块绝对比人强”。人工还在查一些没见过的 API 时AI 可能已经把缺口都跑过一遍了。前提是要用消融方式限制它不要让它在错误假设上无限扩展。五、完整实现流程核心入口是 Python负责三件事初始化会话拿JSESSIONID和SESSION调 Node 生成gdxidpyhxdE和black_box拼Anti-Headers请求搜索接口关键代码如下动态值不写死只能放大致代码#!/usr/bin/env python3importargparseimportjsonimportrandomimportreimportsubprocessfromdatetimeimportdatefrompathlibimportPathfromurllib.parseimportquoteimportrequestsBASE_URL https://www.xxx.comSEARCH_URL f{BASE_URL}/shop/api/shopping/b2c/searchflightPROJECT_DIR Path(__file__).resolve().parents[1]SNAKER_ALPHABET abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZUSER_AGENT (Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/149.0.0.0 Safari/537.36)classFlightSearchError(RuntimeError):passdefrun_node(script: Path, payload: dict, field: str)- str:completed subprocess.run([node, str(script), json.dumps(payload, ensure_asciiFalse, separators(,,:))],cwdPROJECT_DIR,capture_outputTrue,checkTrue,textTrue,timeout20,)value json.loads(completed.stdout)[field]ifnotisinstance(value, str)ornotvalue:raiseFlightSearchError(f动态生成{field}失败)returnvaluedefgenerate_black_box()- str:returnrun_node(PROJECT_DIR /analysis/signature.js, {mode:blackbox},black_box)defgenerate_gdx_cookie()- str:fp run_node(PROJECT_DIR /analysis/netease_signature.js, {},fingerprint)returnquote(fp, safe-_.!~*())defgenerate_snaker_id()- str:chooser random.SystemRandom()return.join(chooser.choice(SNAKER_ALPHABET)for_inrange(16))defcreate_session()- requests.Session:session requests.Session()session.headers.update({Accept:application/json, text/plain, */*,Accept-Language:zh-CN,zh;q0.9,Referer:f{BASE_URL}/zh-CN,User-Agent: USER_AGENT,})session.get(f{BASE_URL}/backoffice/api/system/ip, timeout15).raise_for_status()session.get(f{BASE_URL}/member/api/busi-parameter/getBusiParam?sysTypeB2CmodelTypeREStype9AIR_LOGINcurrentPage1pageSize10,timeout15,).raise_for_status()missing {JSESSIONID,SESSION} - set(session.cookies.get_dict())ifmissing:raiseFlightSearchError(f缺少 Cookie{, .join(sorted(missing))})session.cookies.set(__snaker__id, generate_snaker_id(), domainwww.9air.com, path/)session.cookies.set(gdxidpyhxdE, generate_gdx_cookie(), domainwww.9air.com, path/)returnsessiondefnormalize_code(value: str, label: str)- str:code value.strip().upper()ifnotre.fullmatch(r[A-Z0-9]{3}, code):raiseFlightSearchError(f{label}必须是 3 位机场或城市代码)returncodedefsearch_flights(departure: str, arrival: str, departure_date: str)- dict:departure normalize_code(departure,出发地)arrival normalize_code(arrival,目的地)departure_date date.fromisoformat(departure_date).isoformat()ifdeparture arrival:raiseFlightSearchError(出发地和目的地不能相同)session create_session()anti_headers {takeoff_place: departure,arrive_place: arrival,is_roundtrip:1,departure_date: departure_date,black_box: generate_black_box(),channel:9air_web,}params {language:zh_CN,currency:CNY,flightCondition: (findex:0;depCode:{departure};arrCode:{arrival};depDate:{departure_date};depCodeType:CITY;arrCodeType:CITY;),channelNo:B2C,tripType:OW,groupIndicator:I,adultCount:1,childCount:0,infantCount:0,}response session.get(SEARCH_URL,paramsparams,headers{Anti-Headers: json.dumps(anti_headers, ensure_asciiFalse, separators(,,:)),Referer:f{BASE_URL}/zh-CN/book/booking,},timeout30,)response.raise_for_status()result response.json()ifresult.get(status) !200:raiseFlightSearchError(f搜索失败{result.get(msg)})returnresultdefmain()-None:parser argparse.ArgumentParser()parser.add_argument(departure)parser.add_argument(arrival)parser.add_argument(date)args parser.parse_args()print(json.dumps(search_flights(args.departure, args.arrival, args.date), ensure_asciiFalse, indent2))if__name__ __main__:main()运行方式python3 output/final_solution.py CAN BJS 2026-07-15python3 output/final_solution.py BJS CAN 2026-07-16python3 output/final_solution.py CAN HAK 2026-07-17只要九元航空有对应航线就能正常返回数据没有航线就是正常空列表。六、实测结果轮次航线/日期HTTP/业务数据1CAN → BJS / 2026-07-15200 / 200AQ10011 条行程2BJS → CAN / 2026-07-16200 / 200AQ10021 条行程3CAN → HAK / 2026-07-17200 / 200AQ10231 条行程另外做了两次独立运行四个 Cookie 和black_box都发生变化说明不是硬编码旧值。七、AI 辅助心得7.1 AI 具体做了什么这次我最大的感受是模型越强人工干预越少skill要能够一直持续推进。整个流程我只发了两次 prompt剩下就是让模型按逆向 skill 往下跑。它自己完成了 HAR 分析、前端调用链定位、SDK 入口定位、动态 Cookie 来源拆分、补环境、消融测试和真实请求验证。5.6sol给我的感觉和之前最大的区别是会话压缩之后跑偏概率比较低。这点非常重要。逆向任务经常会跑很久如果压缩一次上下文就开始忘目标、忘约束、乱改方向那后面成本会很高。7.2 成本和效率这次用的是极高档位模型但因为现在 GPT 成本已经很低整个流程没超过 10 块钱。换成人工时间1 小时 44 分钟直接打通动态 Cookie 和black_box这个效率已经很强。现在 AI 越来越强参数越来越多算力成本也越来越高。但只要调用价格继续下降对 IT 行业肯定是巨大冲击。尤其是补环境这种任务AI 的优势很明显它可以很快把大量 API、字段、异常现象跑一遍再通过消融收敛到最小可用环境。7.3 正确用法我建议以后这类任务固定加一个“消融测试”流程做法目的每次只补一个环境点避免多个变量混在一起保留 B0/B1/A1 结果判断必要、有害、中性删除无效补丁防止补环境越来越臃肿记录业务结果而不只看 HTTP避免上报成功但业务失败这次performance.nodeTiming就是典型例子。HTTP 上报是 200SDK 也能返回 token但业务接口失败。如果只看 SDK 返回值很容易继续往错的方向补。总结这次逆向的核心突破black_box不是固定值来自 TrustDecision SDK 实时生成。gdxidpyhxdE是网易 Core 生成的fp需要按浏览器方式编码进 Cookie。根因不是少补环境而是 Node 的performance.nodeTiming被风控采到了。消融测试比盲目补 API 更稳可以快速判断哪些环境项该保留、哪些该删除。目前是补环境版本后续如果要做指纹置换也可以继续交给 AI 做。后面应该还会更一些国际站点的安全防护可能主要还是以补环境形式出现因为这个路径出活快。至于有人问都是 AI 搞的那写这篇文章的意义是什么我的答案很直接你把这篇文章喂给你的 AI可能能帮你省点 token我从你这里获得一个点赞或者关注。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进