资讯动态

登录验证码逆向全链路:从JS加密到滑块轨迹模拟的工程实践

发布时间:2026/10/22 10:54:55 来源:尧图企业网站定制
做爬虫工程和接口自动化的朋友迟早会在登录环节遇上验证码逆向这个坎。前两天我在处理某安的登录流程时把整条链路从头到尾捋了一遍从进入登录页到最终拿到会话态中间涉及JS加密、验证码获取、轨迹上报、服务端校验等多个环节踩了不少坑也整理出一些值得记录的方法论。这篇东西不打算写成入门教程重点放逆向分析的思考路径、验证码识别与轨迹模拟的具体做法、以及工程化落地时那些容易被忽略的细节。所有分析和验证都在测试环境、获得授权的前提下进行如果你打算在生产环境或者未授权的场景里尝试风险需要自己评估承担。1. 登录流程逆向的前期准备与整体分析思路1.1 先把请求链路全貌抓出来再谈细节很多人做登录逆向的习惯是一上来就打开开发者工具点登录抓到一条接口就急着看参数、下断点然后卡在某个加密字段里出不来。正确顺序是反过来的先看全貌再钻细节。打开浏览器无痕窗口进入某安的登录页把开发者工具的Network面板清空开启Preserve log然后手动完成一次真实的登录操作。为什么要手动因为自动化工具脚本、无头浏览器产生的请求链路天然有缺失很多关键配置项和验证码相关请求可能被前端逻辑跳过手动操作能保证链路完整。操作完成后把请求列表按时间顺序梳理一遍。典型情况下你会发现登录链路包含这么几类请求页面初始化配置请求通常返回一些js配置、加密公钥、版本号、设备指纹相关参数。验证码获取请求返回验证码图片或者数据集以及本次验证会话的标识。验证码校验请求提交答案、轨迹、耗时等信息返回校验token。登录主请求把账号、加密后的密码、校验token、设备信息、时间戳等一并提交。建议把每一条请求的Method、URL、请求体字段、响应体关键字段拉成一张表贴在笔记里。这一步很枯燥但价值极高。后续你在逆向某个字段时能立刻追溯到它的出处不至于在加密逻辑的迷宫里绕晕。我习惯把这张表称作“参数血统表”它决定了整个逆向工程是稳步推进还是边做边返工。修水管的师傅不会一上来就拧阀门他会先看整条管道的走向。请求链路就是登录这条管道先把管道画出来再去定位哪段堵了思路会清晰很多。1.2 请求体字段的回溯从参数反推生成逻辑链路梳理清楚了接下来围攻登录主请求的请求体。我习惯先对请求体字段做个粗分类明文固定参数如版本号、渠道号、platform类型这类直接写死即可。用户输入参数账号、密码。动态变化参数时间戳、随机数nonce、签名sign、加密后的密文、deviceId。动态变化参数就是逆向的主要目标。定位它们的生成位置常用三种手段按效率排序第一种全局搜索。把参数名放进Sources面板的Search里搜索。比如字段叫sign直接搜sign或sign。如果JS没有深度混淆一般几步就能命中。注意如果搜索词太短可能刷出一堆无关结果可以带上等号、冒号一起搜比如sign、sign:。第二种XHR断点。在Sources面板的XHR/fetch Breakpoints里给登录接口URL添加断点当请求发起之前代码会暂停此时沿着调用栈往上走就能看到是哪段代码构造了请求体。某安这类站点登录请求通常由axios或fetch发出调用栈里一般能看到config对象被逐步赋值的过程动态参数在哪个环节被塞进去一眼就能定位。第三种Hook原生函数。全局搜不到时最常见的原因是参数在运行过程中动态拼装你搜的字符串根本不存在于源码里或者JS经过重度混淆变量名被打碎重组没法直接搜索。这时候可以Hook一些关键原生函数。比如很多加密逻辑在生成签名前会先调用JSON.stringify把对象序列化你可以通过重写window.JSON.stringify在Console里打印调用堆栈const originalStringify JSON.stringify; JSON.stringify function(obj) { console.log(JSON.stringify called with:, obj); console.log(new Error().stack); return originalStringify.call(this, obj); };运行时只要相关加密逻辑被触发Console里就会自动打印出传入的数据结构和调用来源参数与加密逻辑便暴露无遗。这个技巧在处理混淆JS时属于保命手段也是我认为投入产出比最高的调试方法。提示逆向过程中最重要的一件资产不是代码而是“参数血统表”。每个字段从哪来、在哪一步生成、怎么拼进请求体必须记录清楚。没有这张表今天能调通明天换一个版本就废。2. 验证码体系的功能拆解不止是识别一张图2.1 从接口时序判断验证码的触发与校验机制验证码不是孤立出现的它在整个登录流程里存在严格的前后置关系。以我在某安测试环境里观察到的典型流程为例用户输入账号密码点击登录前端先构造一次验证码获取请求服务端返回一张背景图、滑块图以及本次验证会话的标识常见字段名如challenge、sessionId、captchaId。用户拖动滑块完成识别后前端把答案缺口位置对应位移大概率不是明文直接提交的、滑动轨迹数组、动作耗时、设备上下文信息一并提交到校验接口。校验接口如果返回成功会同时下发一个下一步登录所需的token或者cookie。前端拿到这个token之后把它回填进登录主请求的参数里主请求会再次校验这个token以及绑定的设备信息。这个“二次提交”机制非常关键。只识别了图片、拿到缺口坐标并没有完成登录链路。很多初学验证码逆向的人卡在这里——图片缺口识别出来了轨迹也写了结果登录还是失败就是因为忽略了校验接口返回的token要回填到登录参数中这一环。观察接口时序时还有一个小技巧验证码获取和校验接口的返回体里往往藏着下一步请求需要的参数。你手动完成一次登录对比登录主请求body里的字段凡是你在前面的响应体里见过但不知道赋值来源的参数就是从验证码接口或者配置接口带过来的直接在代码里做状态传递即可。2.2 验证码参数构成与还原要点不同验证码厂商的接口模型差异很大某安这类金融场景里常见的是滑块和点选两种少数场景会上升到无感验证。但还原思路是通用的拿到验证码数据集识别目标再根据校验协议构造答案和上下文。先看获取验证码接口。它通常返回三类东西图片资源大图、背景图、滑块图、带缺口的原图有时会乱序或者分片返回。会话标识用于绑定当前验证过程的唯一ID。辅助信息背景图尺寸、宽度、滑块初始位置偏移量、阈值范围。再看校验接口。它要求提交的内容分为三个维度第一答案本身。滑块场景是一个位移像素值点选场景是按顺序排列的坐标组字符场景是识别出的文本。答案不是光秃秃的一个数通常会带上会话ID和签名。第二行为轨迹。某安场景里轨迹参数通常是一个嵌套数组包含一系列x坐标、y坐标和自起点开始的耗时。坐标不能只落在终点服务端风控会检查轨迹是否覆盖从起点到最终位置附近的全过程缺失中间路径容易被判定为机器人。轨迹的采样点之间应该具备变速特征匀速直线或者每帧固定位移的轨迹在服务端反爬系统眼里基本等同于“我不是人”。第三设备上下文。这个很多时候容易被忽略。验证码系统会采集浏览器指纹、canvas渲染结果、WebGL参数、屏幕分辨率、UA是否包含自动化标记、浏览器插件列表等特征。这些特征与轨迹数据一起进入风控模型。也就是说校验接口的请求必须和设备指纹请求、页面初始化请求保持同一“人设”不能这边指纹是Chrome 120那边UA却是Safari for iPhone。还原这些参数的实证方法很简单在手动登录时保存一份完整请求在自动化代码里把某一个参数去掉或者改成固定值对比服务端返回的差异。凡是被改了就报错、报参数错误、报风控校验失败的字段就是必传字段。逐个字段做替换实验比盲目猜想高效得多。3. 验证码图像识别与轨迹模拟的核心实操3.1 用OpenCV做滑块缺口定位的完整流程滑块验证码识别最基础、也是性价比最高的路子是传统图像处理。某安测试环境的滑块背景图质量相对较高我用Python和OpenCV就能达到不错的命中率不需要一上来就上深度学习模型。核心思路是模板匹配滑块图是已知模板背景大图是搜索区域用滑动窗口的方式在背景图中寻找与滑块图最相似的区域相似度最高的位置就是缺口所在。考虑到真实场景里背景图有复杂纹理和光照差异我会先把图像做预处理再匹配。标准流程如下import cv2 import numpy as np def load_image(path): img cv2.imread(path) if img is None: raise FileNotFoundError(f无法读取图片: {path}) return img def find_gap_offset(bg_img, block_img): # 转灰度去掉颜色信息干扰 bg_gray cv2.cvtColor(bg_img, cv2.COLOR_BGR2GRAY) block_gray cv2.cvtColor(block_img, cv2.COLOR_BGR2GRAY) # 高斯滤波去噪保留边缘结构 bg_blur cv2.GaussianBlur(bg_gray, (5, 5), 0) block_blur cv2.GaussianBlur(block_gray, (5, 5), 0) # 模板匹配CCOEFF_NORMED对光照有较好的鲁棒性 result cv2.matchTemplate(bg_blur, block_blur, cv2.TM_CCOEFF_NORMED) _, max_val, _, max_loc cv2.minMaxLoc(result) print(f匹配置信度: {max_val:.4f}) return max_loc, max_valmax_loc是缺口区域左上角的坐标。用TM_CCOEFF_NORMED是因为它计算的是相关性的归一化结果对整体亮度变化不敏感比TM_SQDIFF实用得多。如果你发现匹配精度不够可以再加一步Canny边缘检测把背景图和滑块图都转换成边缘图再进行匹配能把背景纹理干扰大幅压低缺点是多一道耗时的预处理。拿到缺口的像素横坐标x_offset后滑块实际需要滑动的距离并不是这个坐标值而是用它减去滑块在背景图里的初始横坐标。初始坐标需要从验证码页面配置或者接口返回的数据里读取没有固定值。识别置信度可以做一次判断如果max_val低于0.6说明模板匹配基本不可信可能是背景图被加了干扰线或者滑块图被旋转过此时不要硬提交答案直接放弃本次验证码重新拉取一张长期跑下来成功率反而更高。这个策略我称它为“宁可重试不要盲猜”。3.2 轨迹生成与行为特征拟合一滑就废的根源缺口识别出来了很多人兴冲冲地写一段move_to_element干脆利落一次滑到位结果服务端秒回“验证失败”。原因只有一个轨迹太规整了。真实用户拖滑块时会经历一个复杂的过程鼠标先落在滑块上经过一小段观察和准备时间300毫秒左右开始拖动后速度逐渐增加接近缺口时减速到达目标附近会有轻微的前后抖动和回位修正整个动作的持续时间通常在2到4秒之间。而自动化工具的直线移动轨迹是均匀速度、零抖动、零停顿时长风控系统一抓一个准。一个可用的轨迹生成思路是分阶段产生位移import random def generate_track(distance, total_duration3.0, fps60): track [] steps int(total_duration * fps) current 0 # 前5%的时间用于模拟观察停顿 pause_steps int(steps * 0.05) for i in range(steps): if i pause_steps: current 0 else: process i / steps if process 0.6: # 加速阶段位移量逐步增大 step random.uniform(6, 12) else: # 减速阶段位移量逐渐减小 step random.uniform(2, 6) current step # 模拟轻微抖动确保最终接近目标 current min(current, distance random.uniform(-1.5, 0)) timestamp int((i 1) * 1000 / fps) track.append([int(current), timestamp]) # 最终修正到目标位置 track.append([distance, track[-1][1] random.randint(20, 50)]) return track这段代码产生的轨迹基本具备“先停顿、加速、减速、微调”几个阶段特征比一次性滑过去强很多但它仍然是一个简化模型。实际工程中我会用三次函数或贝塞尔曲线生成连续路径再把轨迹离散成采样点叠加高斯噪声。关键原则是让每个采样点的位移差呈现非均匀分布并且总耗时落在合理区间。还有一点容易被忽略轨迹提交接口接收的坐标可能不是单纯的整数像素值有时是相对滑块的偏移量有时要换算到特定坐标系。观察手动请求里轨迹数组的单位和首点坐标前者通常从0或滑块初始位置附近开始最后一点的x坐标与缺口位置一致但y轴往往有上下几像素的抖动这也是人类行为的特征之一。注意行为轨迹只是风控校验的一个维度某安这类站点还会综合校验设备指纹、浏览器环境、请求频率、登录历史等多个信号。只修轨迹不修整体环境依然可能触发验证失败。4. 逆向实战中最常见的坑与排查技巧4.1 高频问题清单与检查表我把实际测试中反复遇到的典型问题整理成了一张速查表遇到问题按表排查能节省大量时间。现象可能原因排查方向登录接口返回“签名错误”某个动态参数漏传或拼装顺序错误对照手动请求的参数血统表逐一核对字段来源与拼装顺序验证码校验通过但登录接口拒绝校验token过期或未回填检查验证码校验接口返回的token是否成功传入登录主请求滑块总是提示“被风控”轨迹特征太规整或设备指纹与提交环境不符重看轨迹生成逻辑确认设备上下文参数来源保持一致接口提示“时间戳异常”服务器时间与本地时间偏差过大从任意接口响应头读取服务器时间计算offset后统一加在时间戳上请求频率稍高就被限流单IP单会话高频触发风控控制整体请求速率避免并发直冲验证码接口识别接口偶发超时在线识别服务并发上限或网络抖动增加异步重试与队列把识别服务与主流程解耦图像识别定位偏移明显未处理图像缩放或初始偏移量计算错误确认页面中图片实际显示尺寸与原始资源尺寸的缩放比例表格里的问题看起来各不相同但根因往往互相关联。最常见的是第一个和第三个的组合某些加密参数没还原完全签名不对加上轨迹又不自然两个校验同时失败。所以建议做排查时先把参数补齐、签名调通再回头优化轨迹和风控特征不要同时改三个变量。4.2 对比法与二分法快速锁定差异项排查验证码问题时最有效的两类方法是对比法和二分法。对比法也叫差异分析。手动浏览器完成一次登录Network面板里右键请求复制为cURL然后把cURL导入请求工具与自动化代码的请求做逐字段对比。差异项一目了然多出来的参数、不一样的顺序、变化的时间戳都可以快速定位。cURL本身可以直接在命令行执行也可以转换成Python requests代码它是定位请求差异的黄金标准。二分法的核心是控制变量。每次只修改一个参数观察服务端返回变化。比如怀疑traceId参数无效就把值改成随机字符串发送看返回码是否变化。如果改成什么值都返回成功且登录成功说明这个参数可能是埋点用途不参与服务端校验。如果稍微一改就报错它就是关键校验字段需要重点还原。这个方法虽然朴素但是在面对十几个未知参数时效率远高于瞎猜。某安登录接口的JS经过混淆之后直接跟踪参数赋值路径非常痛苦。这种情况下我更推荐插桩配合二分法重写关键原生函数打印出入参数和调用堆栈在Console里手动执行关键步骤逐步缩小范围。把断点打在登录请求发出去前的最后一步查看最终请求体里每一个值在内存中的存储对象再反向推导对象是从哪里来的。这条路线比逐行读混淆代码要快得多也更好落地。5. 验证码识别工程的落地方式与长期维护思考5.1 各类识别方案的适用边界与成本对比验证码识别技术方案的选择本质上是在准确率、成本和维护复杂度之间做取舍。我按实际项目经验把常见方案做了横向对比方案接入成本单次成本准确率适合场景主要瓶颈在线打码平台低按API接入按次计费高中小规模、临时项目成本随流量线性增长并发受限OpenCV模板匹配低本地运行几乎为零中受图型变化影响大模板固定的内部系统换一套图型或旋转干扰就失效深度学习目标检测高需标注训练数据低模型推理高长期高频、图型多变场景数据集建设与模型迭代成本高混合方案规则模型中低中上生产环境通用架构复杂度增加需要持续调优在线打码平台是最快的路径接口文档成熟几行代码就能接好准确率通常也很稳但每识别一次都产生费用。流量小的时候无所谓一旦规模化成本立刻变得扎眼。某安这类登录验证码单日百万次识别就是一笔不小的开销。OpenCV方案零成本适合快速验证和内部系统。它对付固定模板、清晰背景的滑块图绰绰有余。但是一旦背景增加干扰线、滑块被随机旋转、或者验证码供应商升级图型准确率就会断崖式下跌。这个方案适合“够用”的场景不适合长期对抗。深度学习方案是长期主义的选择。用YOLO系列或者PaddleOCR这类框架训练一个缺口检测或者文字识别模型对复杂背景的适应性远超传统图像处理。但代价是数据标注、GPU训练、模型部署和持续迭代对小团队来说不是一笔小投入。我个人的工程建议是混合方案先用OpenCV快速识别并输出置信度max_val较高的请求直接用结果低置信度的请求丢给在线打码平台兜底同时把低置信度的样本回流到训练集里逐步提高本地模型的覆盖面。这样既控制成本又不牺牲整体成功率。5.2 工程化落地的稳定性设计验证码逆向一旦进入生产环境难点就不在识别算法而在工程稳定性。几个经过验证的落地设计值得参考第一把验证码识别服务独立部署。不要在主流程代码里同步调用识别接口而是通过消息队列或者异步任务把验证码识别请求抛出去识别完成后回调通知。主流程不关心识别过程有多慢只关心最终结果。这样即使识别服务抖动或者在线平台超时也不会拖垮整个登录服务。第二做失败降级与重试。识别服务内部要有清晰的状态机识别失败、校验失败、超时、置信度低对应不同的处理策略。校验失败时不要反复用同一张图重试应该重新拉取验证码再走一遍流程避免在同一张图上死磕。第三全链路日志打点。验证码服务的每个环节都要输出结构化日志识别耗时、识别置信度、校验结果、风控错误码、轨迹特征统计。长期积累这些数据后你可以统计出当前识别阈值是否合理、风控策略是否有变化。某天成功率突然下降通过日志对比发现风控错误码从“参数错误”变成了“设备风险”就能快速意识到是设备指纹维度的校验加强而不是识别算法出了问题。第四请求频率与并发控制要温和。高频集中请求同一账号、同一IP很容易触发风控模块的全局限流。即使验证码本身识别正确也会被拒绝。因此工程实现上要有限速器把登录请求的发起间隔控制在一个安全的范围内并且在分布式部署时注意把同一账号或同一来源的请求绑定到有限的出口节点上。最后分享一个小技巧最后说一个我在实际项目里受用很久的做法把某安的验证码获取接口和校验接口单独抽出来做成一个本地的mock server。在开发登录主流程的时候直接用mock接口返回固定的校验token这样不必每轮调试都跑一次真实验证码逻辑开发速度提升非常明显。等到主流程稳定之后再把mock server替换成真实的识别链路两者互不干扰。我看到太多人一上来就把主流程和验证码识别强耦在一起结果每改一次登录逻辑都要花几十秒过一遍真实验证码调试体验极其痛苦。先解耦、再对接这个习惯帮我省下了大量联调时间也推荐给正在做登录流程自动化的你。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑