新闻详情

新闻详情

首页 / 资讯中心 / 详情

东方航空m端航班价格查询逆向实录:从抓包到签名还原与数据采集

发布时间:2026/9/30 8:31:36来源:尧图网络
东方航空m端航班价格查询逆向实录:从抓包到签名还原与数据采集
做航班价格采集的人大概都头疼过同一个问题聚合平台的数据好抓但一手数据永远在航司自己手里。我最近在弄一个低价提醒的小工具需求很简单——每天查几次特定航线的往返票价低于心理价位就推一条通知。数据源绕不开东方航空官方渠道于是就有了这篇m端逆向实操记录。先交代一下背景。所谓“m端”就是航空公司的移动端网页通常挂在m.ceair.com或者类似的子域名下面向手机浏览器访问。和完整的App相比m端的代码量小、更新频率相对可控而且本质上还是一个Web页面前端逆向技术的通用手段基本都能用上。相比之下东方航空App的逆向就要麻烦不少涉及安卓逆向那一套流程得处理加固壳、so层逻辑、Frida Hook等等对只是想拿个航班价格的人来说投入产出比太低了。这篇内容我按自己实际走过的路径来写从接口定位、加密参数分析、签名算法还原到最后怎么把它工程化落地跑稳定。整个过程用的是最常规的浏览器调试器加Node.js补环境方案不需要太高门槛也不需要背任何逆向框架文档——说白了一个有前端基础、能看懂XHR请求的人照着操作一遍就能上手。1. 为什么盯上东方航空m端而不是App或开放平台先说需求层面的判断很多人一上来就想着去逆向App我觉得这属于路线选择失误。航司App的逆向常规做法是把APK拉下来用jadx反编译看java层的代码逻辑然后对着Smali代码加日志、重打包遇到加固壳还得先脱壳再把可疑函数挂到Frida上做动态调试。整个过程不是不能做而是时间成本高。我见过不少朋友在“frida逆向工具比较”“app逆向”“安卓逆向”这些话题下花了很多时间最后发现目标App只是WebView套壳核心接口照样走的是一套Web协议——你前面那些脱壳工作全白干。m端Web逆向就不一样。它跑在浏览器里所有请求和响应都能被开发者工具完整看到加密逻辑以JavaScript形式直接下发到前端。这就意味着只要定位到关键函数还原整个签名过程是件相对确定的事。再加上m端一般不会做太重的代码保护顶多压缩混淆一下跟App那种so层算法完全不是一个难度等级。当然也有人会问为什么不走官方开放平台我试过原因很现实开放平台对个人开发者不友好申请资质、签约流程一套走下来周期很长而且开放接口的覆盖范围、频率限制都不一定满足个人工具的需求。对于“每天查三次价格”这种低频场景从m端拿数据反而更直接。还有一个容易被忽略的点m端的请求结构往往和App端是同一套接口网关只可能在加密参数上略有差异。把m端这条路跑通之后如果哪天真需要去碰App端你至少已经把接口语义、数据结构、签名规则的公共部分都摸清了省钱省力。所以我最终确定了技术路线Chrome开发者工具定位请求全局搜索加密参数断点回溯签名函数Node.js补环境最后用Python组装并发请求。2. 抓包定位航班查询接口从一条请求开始逆向的第一步永远是抓包这一步的目的不是分析加密而是搞清楚“服务器到底需要哪些参数、返回了什么数据”。打开东方航空m端首页找到航班查询入口。不用急着登录匿名状态一般就能查航班和价格。进入页面之后先把Chrome开发者工具打开Network面板勾选上Preserve log防止页面跳转时清空记录然后在页面上输入出发地、目的地、日期点击查询。请求发出去之后Network面板里会刷出一批XHR或Fetch请求。这时候需要做的事是筛选先按Fetch/XHR过滤再去看URL里有没有flight、search、price、schedule这类关键字。通常航班查询的接口URL会比静态资源长很多而且带着一堆query参数一眼就能认出来。我这次遇到的接口路径结构大致是这样请求URL以/searchService或/queryApi开头方法为POST请求体是JSON。找到目标请求之后右键点击它选择Copy as cURL。把这个命令粘到终端里跑一次先验证一件事直接重放这个请求服务器会不会正常返回航班数据。这一步得到的反馈很关键基本分两种情况如果直接返回数据说明当前这套接口还没有签名校验这个项目可以简化一大半。如果返回401、403或者提示sign error、invalid token那就说明请求里的某个参数是动态加密的我们需要继续往下挖。我在东航m端遇到的是第二种情况而且错误信息相当明确直接提示签名校验失败。这反而好办因为错误类型已经告诉你了问题出在某个需要动态计算的参数上。接下来看请求体里的字段。一般分成两类业务明文参数出发城市、到达城市、日期、航程类型、乘客数、舱位代码。这些是可读的直接暴露在JSON里。加密动态参数大部分情况下会有一个sign或者signature字段也有一些接口会放在特定的header里比如x-sign、x-token。偶尔还伴随一个timestamp或nonce。把请求体重放时可以手动改几个字段来验证哪些参数影响签名。比如只改日期保留原来的sign重放一次如果报错说明签名和业务参数是绑定的如果正常返回说明参数没参与计算。别小看这一步它能帮你把判断范围缩小很多。如果你观察得够细还会发现timestamp这个字段每次点击查询都不一样。这种情况下签名大概率把时间戳也吃进去了用来防止重放攻击。这就是为什么直接复制cURL重放会失败——时间戳早过期了。3. 顺着sign参数找到加密函数断点与调用栈实战定位到sign参数之后真正的逆向分析才开始。这里我说的“逆向”其实就是顺着JS代码反推出签名函数的输入、处理和输出。很多教程喜欢直接说“搜索参数名”但实际操作中光靠搜索往往一头雾水因为压缩后的JS文件里带sign关键字的地方可能有几十处根本分不清哪个是我们要的。我习惯优先看Initiator面板。在Network面板点开目标请求右侧会有Initiator一栏点进去能看到发起该请求的JS调用栈。这个调用栈是浏览器自动记录的直接从栈顶往下一层一层点就能看到请求是在哪个函数里fetch或xhr.send的然后在附近找sign的赋值语句。大多数情况下签名函数的调用点就在请求构造函数上方两三行属于“近水楼台”的位置。如果你用的调试器版本比较老Initiator信息不够清晰那就用笨办法在Sources面板里按CtrlShiftF全局搜索sign字段名。搜索结果会有很多怎么筛我的经验是优先找符合这三个条件的文件文件名带search、query、flight、config相关字样。文件体积不大几十KB到两三百KB之间太大的一般是公共库太小的一般是挂载脚本。文件里有sign和请求URL出现的上下文关联。定位到疑似赋值点之后在那个JS文件里找到签名函数的定义然后直接下断点。重新在页面上触发一次查询断点命中后看Scope面板观察函数入参再开Call Stack面板一点一点往外层回溯。这一步基本就能看到整个签名的生成链路了。下面这个示例只是签名函数的一种常见形态我用它来说明套路不是东航的真实代码。搞清楚结构比抄到现成代码重要得多function generateSign(params) { var keys Object.keys(params).sort(); var raw keys.map(function(k) { return k params[k]; }).join(); var time new Date().getTime(); var finalStr raw timestamp time salt你的盐值; return md5(finalStr).hexdigest(); }这类函数拆开来看核心操作无非四件事参数排序、拼接字符串、加固定盐值、算摘要。算法本身不复杂大部分航司类Web站点的签名都逃不出这个框架。困难往往在细节上比如参数排序规则是字典序还是根据接口文档自定义序、盐值是写死的还是在代码里动态生成、摘要算法是MD5还是SHA256、是否先做了HMAC再做十六进制编码——这些信息只能靠断点来验证不能拍脑袋猜。有一个坑我要特别提醒不要看到timestamp就以为它是签名密钥。很多接口里时间戳只是作为防重放参数存在和签名计算无关。判断方法很简单把时间戳字段从请求体里去掉用同一个签名重放如果服务器不报错说明时间戳没参与计算如果报错再把它拼进签名逻辑里做测试。另外搜索JS代码时要注意压缩混淆的情况。生产环境的JS几乎都是压缩过的变量名可能叫t、e、n看着很劝退。我的对策是先找人名化程度高的文件——有些模块只是做了uglify压缩但保留了函数名有些甚至保留了注释从这些文件入手会顺利很多。如果你运气不好所有文件和函数名全是混淆过的那就在断点命中后多花点时间看Call Stack把整个调用链的输入输出走一遍一样能还原逻辑只是时间会翻倍。顺带说一句断点调试这个阶段最好把浏览器自带的Overrides功能用起来。把目标JS文件保存到本地结合本地替换可以自由地在签名函数里加日志、改逻辑不用每次刷新页面都重新梳理一遍压缩代码。这是一个能让效率翻倍的操作建议尽早学会。4. 把签名算法搬进本地运行补环境与结果验证定位到签名算法之后接下来的目标是脱离浏览器环境在我们自己的代码里把签名算出来。这一步最常见的做法就是把签名相关的那段JavaScript代码原封不动地拿到Node.js里运行然后由Python或Node主程序负责发起HTTP请求。但这里有一个问题这段JS是写在浏览器环境里的运行时可能依赖很多浏览器对象比如window、document、navigator、localStorage。Node.js默认只有V8引擎不提供这些全局对象直接node运行会报各种xxx is not defined错误。补环境就是针对这些缺失的全局变量一个一个补上去让这段JS以为自己在浏览器里运行。我的做法是这样的第一步把前面定位到的签名函数以及它依赖的工具函数、常量定义从源JS文件里完整拷贝出来单独存成一个sign_core.js。第二步在Node项目里建一个入口文件先声明缺失的全局变量再require或eval这段代码。补环境时有一个优先级讲究先补最常见的三个window、navigator、document。代码类似这样global.window {}; global.window.navigator { userAgent: Mozilla/5.0 (iPhone; CPU iPhone OS 16_6 like Mac OS X) ..., platform: iPhone, language: zh-CN }; global.navigator global.window.navigator; global.document {}; global.document.cookie ;第三步调用签名函数传一组测试参数进去把输出结果记下来。第四步回到浏览器里在DevTools的Console里手动调用原始页面的签名函数同样调用一组参数对比两边的输出是否一致。前后一致说明补环境基本到位不一致很可能是某个全局变量或者随机数生成逻辑没补全。这里有一个很容易被忽略的检查点有些JS代码会检测函数是否被Hook过常见手段是调用函数的toString()看源码是否和预期一致。如果你在调试阶段给页面里的签名函数打过补丁浏览器环境里的函数源码其实已经被你修改过了对比结果会有误导性。所以验证的时候尽量在全新页面上操作别用改过的文件做基准。补环境过程中还有一个高频报错是小写的window有了但window.a内部的某个属性缺失比如window.location.href、window.screen.width。这些属性报错时根据报错信息补上就行。另一个高频坑是代码里用了document.createElement(div)或document.getElementById这种DOM操作在补环境阶段很难完全模拟。我的经验是——如果签名函数本身不需要DOM操作就不要把整段包含DOM逻辑的代码拷进来尽量只保留签名计算路径上的函数和常量。抠函数的过程要克制不要贪多。Node里跑起来之后有人可能还会问能不能用Frida直接HookFrida确实是动态调试的神器尤其是安卓逆向和App逆向场景市面上关于“frida逆向工具比较”“app逆向”的讨论也很多。但对m端Web项目来说用Frida反而绕远了——浏览器本身就是完美的调试环境补环境也很轻量。除非你面对的是某个嵌在原生App里的WebView页面需要直接在真机上Hook那才轮到Frida上场。补环境跑通之后签名算法这块就算彻底拿下了。接下来要解决的是工程化落地的问题。5. 工程化落地从“算出签名”到“稳定取数”要过的几道坎能算出签名只是第一步离“稳定取数”还有很长一段路。这个阶段踩的坑比逆向阶段多得多。我把实际遇到过的问题按出现频率排队一个一个说。第一道坎是时间戳对齐。签名里如果包含时间戳而本地时间和服务器时间差得太多请求大概率会被拒绝。我在本地测试时遇到过一种情况Windows系统时间慢了30秒签名按本地时间生成服务器直接返回403。解决办法是在代码启动时先做一次时间校准——请求东航服务端的某个公开接口读取响应头里的Date字段计算出本地时间和服务器时间的偏移量后续生成签名时统一加偏移量。这个做法对任何带有时间戳签名的接口都通用建议直接封装成工具函数。第二道坎是Cookie与会话管理。m端的某些接口匿名状态下就能访问但要求请求头里携带当前页面的Cookie尤其是route、sessionId这类维持会话的参数。Cookie过期了签名再对也会被拒。我的处理方式是把Cookie维护成一个独立的模块第一次访问首页拿到初始Cookie然后一直复用如果收到特定错误码自动重新获取Cookie再重试。有些功能走会员价时Cookie里还需要保持登录态那就更复杂一点登录后的token和Cookie要定期刷新不能写死。第三道坎是频率限制和风控。不要小看这个航司的接口风控比普通小网站聪明得多。刚开始测试时我写了个循环脚本一口气跑了30次查询结果第15次左右返回了一个异常页面提示需要滑块验证。遇到这种情况单纯换IP不是好办法更务实的做法是控制请求节奏单次查询间隔至少2秒单会话并发数控制在3以内UA随机切换必要时在两次查询之间模拟一次正常的页面访问让服务端觉得这是一个真人在使用。第四道坎是响应数据可能也是加密的。有些接口返回的JSON是明文但东航m端的部分接口返回的数据不是直接的业务字段而是一段加密的字符串需要前端JS做解密才能看到航班列表。处理方式也很直接和签名函数一样在Sources里搜索解密函数的关键特征比如decrypt、AES、RSA、CryptoJS找到之后把解密逻辑同样抽出来在本地补环境里跑。解密用的密钥一般在页面JS里写死或者通过另一个接口下发找到它的位置剩下的就是常规的密码学操作还原了。第五道坎是异常分类。经过一段时间听跑我总结了一套错误码分类规则放在代码里做分流处理签名错误单独一类一般是代码改动或算法变了Cookie失效单独一类默认触发重新登录流程风控拦截单独一类触发降速处理参数错误单独一类说明业务字段拼错了。把这几类错误码分开能省掉大量排障时间。光凭响应文本去猜状态容易把问题带偏。代码结构上我强烈建议不要把签名算法直接埋在爬虫脚本里而是独立成一个子模块通过一个配置接口传入参数、返回签名结果。这样一旦签名算法变了只需要更新签名模块主程序基本不用动。我这次是分成四个文件sign.js管签名计算request.py管请求发送和重试config.json管接口地址、参数模板、频率设置main.py管调度和结果存储。模块清晰的好处不用多说维护的时候谁用谁知道。6. 边界、合规与长期维护逆向技术本身是中性的但怎么用必须讲清楚。我这次做的低价提醒工具查询频率极低一天只有几次本质上和一个真人用户在手机上查票没有区别不构成对服务端的压力。这应该成为一个默认的开发底线。具体来说有几点自我约束供参考第一不做大规模抓取更不做批量爬取后再转售数据的事情第二不碰涉及个人隐私的接口比如会员信息、实名认证、票号查询这一类这些接口即使是技术上有办法绕过鉴权也绝对不能碰第三如果查询频率进入每分钟几十次的量级那就不是个人工具的范畴了应该直接去联系官方谈合作或走开放平台而不是继续和风控对抗。另外还要有长期维护的心理准备。m端页面前端一改版签名算法就可能跟着变。应对方式是在代码里做一个轻量监控每次取数成功时记录当前用到的JS文件哈希值和签名函数的特征注释如果连续三次请求都报签名错误大概率是页面改版了优先去重新抓包分析新的签名逻辑而不是盲目调参数。还有一点经验签名算法找回不来的时候不要立刻从头开始逆向。先去Network面板里抓几个最新的请求看看请求体里新增了哪些字段旧的字段是否被删掉了。很多时候前端只是顺手改了一下拼接顺序或者加了一个新的nonce字段按增量变化的思路去更新签名逻辑比全量重审快得多。最后说一句实在话m端逆向这类事最花时间的环节从来不是解密算法本身而是“定位”。从打开调试器到最终找到签名函数我第一次做东航这个目标用了一个多小时其中大半时间都耗在压缩代码里翻找和验证上。一旦走通一次你就会发现所有航司类m端的套路都极其相似——参数排序、拼串、加盐、摘要翻来覆去就那几样。自己整理一份逆向Checklist把搜索参数名、看Initiator、断点回溯、补环境验证这几个标准动作固化下来之后遇到任何同类目标都会快很多。
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

GPU显存不够怎么办?从OOM报错到优化策略的全面解析 2026/9/30 9:27:52

GPU显存不够怎么办?从OOM报错到优化策略的全面解析

1. GPU显存不够到底会发生什么先把结论摆在最前面:GPU显存不够,最直接的后果就是OOM(Out Of Memory)报错,程序直接崩掉。但实际情况远比“崩掉”两个字复杂得多。我见过太多人第一次遇到显存问题时一脸懵——明明任务管…

阅读更多 →
Unity URP PBR材质实战:从参数原理到金属塑料质感调优 2026/9/30 9:27:52

Unity URP PBR材质实战:从参数原理到金属塑料质感调优

1. 从零搞懂PBR:为什么你的材质看起来总像塑料1.1 一个让我纠结了三个月的画面差异刚接触URP管线那会儿,我做过一个特别蠢的对比测试。同一个金属球模型,我用传统Lambert光照调了一版,又用PBR流程调了一版,然后截了两张…

阅读更多 →
大模型量化实战:从显存估算到量化档位选择 2026/9/30 9:27:52

大模型量化实战:从显存估算到量化档位选择

1. 从一张显卡跑不动大模型说起 很多人第一次接触本地部署大模型,卡住的地方不是代码写不出来,而是显存不够。你下载了一个几十 GB 的模型权重,兴冲冲地加载,结果程序直接抛出显存溢出的错误,连对话界面都进不去。这时…

阅读更多 →
音频美术流程全解析:从时间轴对齐到空间音频可视化 2026/9/30 9:27:52

音频美术流程全解析:从时间轴对齐到空间音频可视化

1. 音频美术流程到底在解决什么问题“莫提斯”都能看懂的音频美术相关流程——这个标题我第一次看到的时候,脑子里蹦出来的第一个念头是:终于有人要把音频和美术这两条平时各干各的线,拧成一股绳来讲了。音频美术,说白了就是游戏、…

阅读更多 →
SpringBoot+Java在线考试系统:从选题到答辩的完整毕设指南 2026/9/30 9:27:52

SpringBoot+Java在线考试系统:从选题到答辩的完整毕设指南

每年到这个节点,计算机专业的同学基本都逃不过一件事——毕业设计选题。我见过太多人从选题开始就给自己挖坑,有的选了个分布式电商,结果做了三个月还在折腾环境;有的选了个"学生管理系统",做到答辩前发现功…

阅读更多 →
多模型会审代码:三条命令实现AI互补审查与成本优化 2026/9/30 9:27:38

多模型会审代码:三条命令实现AI互补审查与成本优化

1. 从"单打独斗"到"多模型会审":我为什么要折腾这套流程 代码审查这件事,做过几年开发的人都懂,最怕的不是没工具,而是工具太单一。以前我用单个大模型审代码,刚开始觉得挺香,贴一段进…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉