某航参数逆向及设备指纹分析

文章目录

  • 1. 写在前面
  • 2. 接口分析
  • 3. 加密分析
  • 4. 算法还原
  • 5. 设备指纹风控分析与绕过

【🏠作者主页】:吴秋霖
【💼作者介绍】:擅长爬虫与JS加密逆向分析!Python领域优质创作者、CSDN博客专家、阿里云博客专家、华为云享专家。一路走来长期坚守并致力于Python与爬虫领域研究与开发工作!
【🌟作者推荐】:对爬虫领域以及JS逆向分析感兴趣的朋友可以关注《爬虫JS逆向实战》《深耕爬虫领域》
未来作者会持续更新所用到、学到、看到的技术知识!包括但不限于:各类验证码突防、爬虫APP与JS逆向分析、RPA自动化、分布式爬虫、Python领域等相关文章

作者声明:文章仅供学习交流与参考!严禁用于任何商业与非法用途!否则由此产生的一切后果均与作者无关!如有侵权,请联系作者本人进行删除!

1. 写在前面

  今天端午节,祝大家端午安康!最近事情比较多,所以又有很长一段时间没有写文章了(差点忘了这个好习惯~~)。刚好今天过节有时间,把前些天看的一些小案例分享一下。这期分析的是某航空网站的加密参数跟它的设备指纹风控,通过非登录游客身份搜索航班机票查询然后解决风控标记弹行为验证(比较简单适合新手研究


分析网站

aHR0cHM6Ly93d3cuYWlyY2hpbmEuY29tLmNuL2dhdGV3YXkvYXBpL2ZsaWdodC9saXN0

2. 接口分析

随便在搜索入口查询一趟航班信息,可以看到发包请求参数params一段密文,如下所示:

在这里插入图片描述

除了请求参数加密外,请求头也有一个x-device-token参数疑似动态生成的(但不是直接网站的JS代码层面生成的)。如下所示:

在这里插入图片描述

像这种Token请求头的参数一般情况下我们可以先不去管它,先去分析请求参数的加密。头部一般非签名的核心参数,你固定测试一次两次是可以重放的。但是请求参数的加密对什么加密了、明文是什么以及后续能够模拟伪造出请求来测试是必须

初看这个Token的时候我感觉在哪里见过(比较熟悉)。有经验的可能会猜测它是由某个接口动态请求之后服务端下发的(在有效的时间范围可以有效固定去使用)做过某东逆向分析的可以发现它的这个参数开头tak01...跟它们官方的那个设备指纹高度相似(后续验证发现就是用的某东的设备指纹风控)

3. 加密分析

开始定位找到发包加密的位置,这里可以直接通过XHR断点去跟栈就能够溯源到整个发包跟调用加密的位置,如下所示:

在这里插入图片描述

可以看到o.P就是加密方法,直接跳转到对应的JS代码,如下:
在这里插入图片描述

var c = function(e) {try {var t = encodeURIComponent(JSON.stringify(e));return o.sm2.doEncrypt(t, "04064c2a3bcafba2c1ca4f5fb8ecd876b23d70fc4479b78f3c8066c02a8c17749458bca86361bc563d2501b61e2ac93a676a1305893aafcc6be2ea48ecb048672e", a.yV)} catch (n) {return console.log(n),""}}

看上面加密代码的入口,比较明显的可以看到使用了疑似sm2国密算法。像一般我们猜测到了加密算法大致看看是否标准的就可以直接使用自己擅长的语言导个包去进行还原。后面那一串的话看起来就是它的密钥,sm2一般长度256 bit,开头04表示非压缩。后面那64字节(128个十六进制字符),大致如下得出:

04 || <X (64 hex)> || <Y (64 hex)> = 1 + 64 + 64 = 129 hex digits

略微看一下它的那个JS实现,是标准一个sm2。然后要还原这个加密算法的方式可以直接把doEncrypt的JS代码扣出来(webpack)然后导出模块再调用即可。还有就是确定完整个加密算法是标准的还是变异的或者魔改的后用其他语言实现(代码量会大大降低

4. 算法还原

既然是分享,这里扣webpack跟使用纯算还原的方式都说一下。首先跳转到sm2.doEncrypt代码处,开始扣一些JS。扣代码的也是讲究精扣粗扣

这里精扣的话就几百行涉及加密的这几段JS代码就行。新手你全部粗扣下来也无所谓(4W多行-不用在意这些细节-能用就行

在这里插入图片描述

然后再把webpack内部的模块加载函数导出来,模块加载器的结构一般如下所示:

function enc(n) {var f = t[n];if (void 0 !== f) return f.exports;...e[n].call(r.exports, r, r.exports,enc)...return r.exports
}

t[n]: 缓存已加载模块
e[n]: 模块定义函数对象(模块id -> 函数)类似Dict
r.exports: 模块的导出结果

之后找到SM2加密方法的所在模块ID(70686),如下所示:

在这里插入图片描述

那么这个时候我们就可以在JS中直接导出扣下来的webpack模块,重新封装一下加密方法。代码实现如下:

function encrypt(e) {var o = sm2(70686), // 加密模块try {var t = encodeURIComponent(JSON.stringify(e));return 0.sm2.doEncrypt(t, "04064c2a3bcafba2c1ca4f5fb8ecd876b23d70fc4479b78f3c8066c02a8c17749458bca86361bc563d2501b61e2ac93a676a1305893aafcc6be2ea48ecb048672e", 1);} catch (n) {console.log(n);return "";}
}

除了上面说到的扣代码,再就是直接使用导包的方式来还原(前提上面的分析我们已经知道了它是一个标准的加密算法),这里我们直接可以使用NodeJS导出加密模块的方式实现,实现代码如下:

const smCrypto = require('sm-crypto');
const { sm2 } = smCrypto;function encrypt(e) {try {const t = encodeURIComponent(JSON.stringify(e));// 密钥const publicKey = "04064c2a3bcafba2c1ca4f5fb8ecd876b23d70fc4479b78f3c8066c02a8c17749458bca86361bc563d2501b61e2ac93a676a1305893aafcc6be2ea48ecb048672e";return sm2.doEncrypt(t, publicKey, 1);} catch (error) {console.error("加密失败:", error);return "";}
}

这个密钥好像是定期会更新的,然后接下来我们验证一下已经通过逆向分析还原出来的加密算法,对接到单次的请求中是否可以正常拿到接口的响应数据,代码实现如下:

import execjs
import requests
from loguru import logger
from getuseragent import UserAgentdef encrypt_request_data(data):with open("sm2.js", encoding='utf-8') as f:ctx = execjs.compile(f.read()) res = ctx.call("encrypt",data) return resdef send_request(encrypted_data):random_ua_list = ["chrome", "firefox", "safari"]ua = UserAgent(random.choice(random_ua_list))useragent = ua.Random()url = "https://www.xxx.com.cn/gateway/api/flight/list"headers = headers = {"Content-Type": "application/json","Accept": "application/json, text/plain, */*","Sec-Fetch-Site": "same-origin","Accept-Language": "zh-CN,zh-Hans;q=0.9","Accept-Encoding": "gzip, deflate, br","Sec-Fetch-Mode": "cors","Host": "www.xxx.com.cn","Origin": "https://www.xxx.com.cn","User-Agent": useragent,"Referer": "https://www.xxx.com.cn/flight/oneway/pek-ctu/2025-06-04","Content-Length": "846","Connection": "keep-alive","Sec-Fetch-Dest": "empty","X-Locale": "zh-CN","X-Device-Token": "" # 自行获取}data = {'params': encrypted_data,'RequestParameterEncryptionIdentificationBit': True}data = json.dumps(data, separators=(',', ':'))response = requests.post(url, headers=headers, data=data)return response.json()if __name__ == "__main__":# 请求明文参数params = {"Trip": [{"Date": "2025-06-05", "Dep": "PEK", "Arrival": "CTU"}],"Passenger": {"adult": 1, "child": 0, "baby": 0},"notchType": None,"aimPrice": None,"RequestParameterSecurityIdentificationBit": True}encrypted_data = encrypt_request_data(params)logger.info(f'加密参数: {encrypted_data}')result = send_request(encrypted_data)logger.info(f'查询数据: {result}')

运行一下上面封装好的Python请求代码,可以看到是没有问题的。能够正常拿到数据,如下所示:

在这里插入图片描述

5. 设备指纹风控分析与绕过

上面测试的是非登录状态下的情况,其实登不登录都无所谓。它本身是有一个风控参的,整个爬虫的风控也都基于它来开展。就是前面我一开始分析提到的X-Device-Token

这个参数就是设备指纹的信息,用来防护恶意请求的。一个X-Device-Token可以请求的次数在10次以内,浏览器的环境就会被标记再配合风控判定推送行为验证码(点选),如下所示:

在这里插入图片描述

在这里插入图片描述

所以如果需要多次持续的请求查询一些数据的话,要么就是直接再逆向分析点选的协议,拿到验证的Token提交也是可以的。再就是解决这个参数绕过点选。继续进一步分析这个参数发现是使用的某东设备指纹风控(包括这个点选也是某东云的验证码系统)如下所示:

在这里插入图片描述

这个参数收集了【浏览器的指纹CanvasWebGL分辨率、Storage...】以及一些初始化加载行为

在这里插入图片描述

针对这个X-Device-Token参数的对抗方案其实也是有很多种的,第一个就是自己定制魔改,第二个就是使用开源好已经从Chromium源码层修改浏览器指纹信息的方案(外面的指纹浏览器也是可以的

这里我们就简单的用魔改过的方案自己在本地搭一个服务,然后通过注入JS的方式刷票务的接口Hook到最新的这个参数,如下所示:

在这里插入图片描述
经过多次测试,一个设备指纹的新参数在请求风控出现行为验证码的时候,调用测试搭建的刷新设备指纹的服务获取新的X-Device-Token都是可以立即绕过行为验证正常再次请求数据的(因为我们使用的魔改方案、它会认为我们是一个新的设备及浏览器),如下所示:

在这里插入图片描述

它这个不管是自动化浏览器的方案还是接口协议的方案都会遇到行为验证码的风控(它的行为验证不像其他平台是必须要过的、可以规避掉)。然后像这种非登录状态或者游客模式可以访问的爬虫方案,厂商针对的风控一般只会从IP设备指纹开展

最后多说一句(爬虫目前想要持续抓取一些头部平台的数据、除了很普遍的很基本的接口验签逆向外。需要解决的就是风控,风控涉及的细分领域有很多。而其中最常遇见的就是设备指纹风控跟行为验证风控,那么对抗是对抗的什么呢?就是这一系列的风控防护,所以定制或魔改指纹、改机这些都是需要涉及的。以前可能只需要考虑策略,但那已经是S3赛季了...

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.pswp.cn/web/82032.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Python训练营---Day41

DAY 41 简单CNN 知识回顾 数据增强卷积神经网络定义的写法batch归一化&#xff1a;调整一个批次的分布&#xff0c;常用与图像数据特征图&#xff1a;只有卷积操作输出的才叫特征图调度器&#xff1a;直接修改基础学习率 卷积操作常见流程如下&#xff1a; 1. 输入 → 卷积层 …

【Netty系列】Reactor 模式 2

目录 流程图说明 关键流程 以下是 Reactor 模式流程图&#xff0c;结合 Netty 的主从多线程模型&#xff0c;帮助你直观理解事件驱动和线程分工&#xff1a; 流程图说明 Clients&#xff08;客户端&#xff09; 多个客户端&#xff08;Client 1~N&#xff09;向服务端发起连…

前端开发中 <> 符号解析问题全解:React、Vue 与 UniApp 场景分析与解决方案

前端开发中 <> 符号解析问题全解&#xff1a;React、Vue 与 UniApp 场景分析与解决方案 在前端开发中&#xff0c;<> 符号在 JSX/TSX 环境中常被错误解析为标签而非比较运算符或泛型&#xff0c;导致语法错误和逻辑异常。本文全面解析该问题在不同框架中的表现及解…

【Web应用】 Java + Vue 前后端开发中的Cookie、Token 和 Swagger介绍

文章目录 前言一、Cookie二、Token三、Swagger总结 前言 在现代的 web 开发中&#xff0c;前后端分离的架构越来越受到欢迎&#xff0c;Java 和 Vue 是这一架构中常用的技术栈。在这个过程中&#xff0c;Cookie、Token 和 Swagger 是三个非常重要的概念。本文将对这三个词进行…

投稿Cover Letter怎么写

Cover Letter控制在一页比较好&#xff0c;简短有力地推荐你的文章。 Dear Editors: Small objects detection in remote sensing field remains several challenges, including complex backgrounds, limited pixel representation, and dense object distribution, which c…

创建型设计模式之Prototype(原型)

创建型设计模式之Prototype&#xff08;原型&#xff09; 摘要&#xff1a; Prototype&#xff08;原型&#xff09;设计模式通过复制现有对象来创建新对象&#xff0c;避免重复初始化操作。该模式包含Prototype接口声明克隆方法、ConcretePrototype实现具体克隆逻辑&#xff…

spark在执行中如何选择shuffle策略

目录 1. SortShuffleManager与HashShuffleManager的选择2. Shuffle策略的自动选择机制3. 关键配置参数4. 版本差异(3.0+新特性)5. 异常处理与调优6. 高级Shuffle服务(CSS)1. SortShuffleManager与HashShuffleManager的选择 SortShuffleManager:默认使用,适用于大规模数据…

AUTOSAR图解==>AUTOSAR_EXP_AIADASAndVMC

AUTOSAR高级驾驶辅助系统与车辆运动控制接口详解 基于AUTOSAR R22-11标准的ADAS与VMC接口规范解析 目录 1. 引言2. 术语和概念说明 2.1 坐标系统2.2 定义 2.2.1 乘用车重心2.2.2 极坐标系统2.2.3 车辆加速度/推进力方向2.2.4 倾斜方向2.2.5 方向盘角度2.2.6 道路变量2.2.7 曲率…

26考研——文件管理_文件目录(4)

408答疑 文章目录 二、文件目录1、目录的作用与结构1.1、目录的基本概念1.2、目录的组织形式1.2.1、单级目录结构1.2.2、两级目录结构1.2.3、多级&#xff08;树形&#xff09;目录结构1.2.4、无环图目录结构 1.3、目录的实现方式1.3.1、线性列表1.3.2、哈希表 2、文件共享与链…

Maven 项目中集成数据库文档生成工具

在 Maven 项目中&#xff0c;可以通过集成 数据库文档生成工具&#xff08;如 screw-maven-plugin、mybatis-generator 或 liquibase&#xff09;来自动生成数据库文档。以下是使用 screw-maven-plugin&#xff08;推荐&#xff09;的完整配置步骤&#xff1a; 1. 添加插件配置…

WebSocket指数避让与重连机制

1. 引言 在现代Web应用中&#xff0c;WebSocket技术已成为实现实时通信的重要手段。与传统的HTTP请求-响应模式不同&#xff0c;WebSocket建立持久连接&#xff0c;使服务器能够主动向客户端推送数据&#xff0c;极大地提升了Web应用的实时性和交互体验。然而&#xff0c;在实…

本地部署AI工作流

&#x1f9f0; 主流 RAG / 工作流工具对比表&#xff08;含是否免费、本地部署支持与资源需求&#xff09; 工具名类型是否支持 RAG可视化目标用户是否免费支持本地部署本地部署一般配置Dify企业级问答系统平台✅✅非技术 & 企业用户✅ 免费版 商业版✅ 支持2C4G 起&…

React 第五十节 Router 中useNavigationType的使用详细介绍

前言 useNavigationType 是 React Router v6 提供的一个钩子&#xff0c;用于确定用户如何导航到当前页面。 它提供了关于导航类型的洞察&#xff0c;有助于优化用户体验和实现特定导航行为。 一、useNavigationType 核心用途 1.1、检测导航方式&#xff1a; 判断用户是通过…

4.2.3 Spark SQL 手动指定数据源

在本节实战中&#xff0c;我们学习了如何在Spark SQL中手动指定数据源以及如何使用format()和option()方法。通过案例演示&#xff0c;我们读取了不同格式的数据文件&#xff0c;包括CSV、JSON&#xff0c;并从JDBC数据源读取数据&#xff0c;展示了如何将这些数据转换为DataFr…

【AUTOSAR OS】计数器Counter机制解析:定义、实现与应用

一、Counter的定义与作用 在AUTOSAR Classic Platform&#xff08;CP&#xff09;中&#xff0c;**Counter&#xff08;计数器&#xff09;**是系统实现时间管理的核心组件&#xff0c;用于测量时间间隔、触发报警&#xff08;Alarm&#xff09;和调度表&#xff08;Schedule …

在机器视觉测量和机器视觉定位中,棋盘格标定如何影响精度

棋盘格标定是机器视觉(尤其是基于相机的系统)中进行相机内参(焦距、主点、畸变系数)和外参(相机相对于世界坐标系的位置和姿态)标定的经典且广泛应用的方法。它的质量直接、显著且多方面地影响最终的视觉测量和定位精度。 以下是棋盘格标定如何影响精度的详细分析: 标定…

SOC-ESP32S3部分:21-非易失性存储库

飞书文档https://x509p6c8to.feishu.cn/wiki/QB0Zw7GLeio4l4kyaWQcuQT3nZS 非易失性存储 (NVS) 库主要用于在 flash 中存储键值格式的数据。 它允许我们在芯片的闪存中存储和读取数据&#xff0c;即使在断电后&#xff0c;这些数据也不会丢失。 NVS 是 ESP32 flash&#xff…

让大模型看得见自己的推理 — KnowTrace结构化知识追踪

让大模型“看得见”自己的推理 —— KnowTrace 结构化知识追踪式 RAG 全解析 一句话概括:把检索-推理“改造”成 动态知识图构建任务,再让 LLM 只关注这张不断精炼的小图 —— 这就是显式知识追踪的核心价值。 1. 背景:为什么 RAG 仍难以搞定多跳推理? 长上下文负担 传统 I…

新版智慧景区信息化系统解决方案

该智慧景区信息化系统解决方案以云 + 大数据 + 物联网技术为核心,秉持 “汇聚联合,突显数据隐性价值” 理念,通过数据融合、业务融合、技术融合,构建 “营销、服务、管理” 三位一体模式。方案涵盖智慧票务、智能入园、精准营销、景区管理(如用电安全监测、森林防火、客流…

人工智能在智能健康监测中的创新应用与未来趋势

随着人们健康意识的不断提高和医疗资源的日益紧张&#xff0c;智能健康监测作为一种新兴的健康管理方式&#xff0c;正在迅速发展。人工智能&#xff08;AI&#xff09;技术通过其强大的数据分析和预测能力&#xff0c;为智能健康监测提供了重要的技术支持。本文将探讨人工智能…