滑块验证码前端安全研究:以 360 天御(TianYu)为例

免责声明: 本文所有分析均基于公开可访问的前端 JS 代码及 360 天御官网演示页(https://tianyu.360.cn/#/global/details/sliding-puzzle),仅用于安全研究、学习与了解验证码防护机制。文中所有接口地址来自官方公开演示环境,不涉及任何第三方业务系统。请勿将本文技术用于任何未授权的系统,违者后果自负。

一、背景介绍

360 天御是奇虎 360 旗下的人机验证方案,本文以滑动拼图验证为研究对象,分析其前端安全机制。

基本交互逻辑:

  1. 前端携带 appId 等设备信息请求 auth 接口,获取背景图(bg)、滑块图(front)、会话标识(token)
  2. 背景图以列乱序方式传输,需依据图片 ID 计算还原顺序后重组
  3. 使用计算机视觉识别滑块缺口位置,得到 distance
  4. 生成拟人化滑动轨迹,经 RSA 分块加密 后构造 report 参数
  5. 携带 reportlength 等参数提交 check 接口,服务端返回 result: true/false

研究核心难点:

  • 图片列乱序还原(基于图片 ID 的置换算法)
  • 多策略融合缺口识别(OpenCV 四种策略 + 置信度聚类)
  • RSA 分块加密轨迹数据(自定义分块边界 + PKCS1_v1_5)

二、整体流程图

复制代码
生成 timestamp / nonce(本地毫秒时间戳)
  ↓
auth 接口(POST /api/v3/auth)
  ↓ 返回 bg URL、front URL、captchaId、token
下载背景图(乱序)+ 滑块图
  ↓
根据图片 ID 计算列置换表 → 重组背景图
  ↓
OpenCV 四策略融合识别缺口距离 distance(原图坐标)
  ↓
换算为压缩宽度坐标(300px 归一化)
  ↓
生成拟人化滑动轨迹 track
  ↓
RSA 分块加密 track → encrypted_track
report = encrypted_track + MD5(captchaId + token)
  ↓
check 接口(POST /api/v3/check)→ result: true/false

三、抓包分析

3.1 auth 接口

请求:

复制代码
POST https://captcha.jiagu.360.cn/api/v3/auth
Content-Type: application/x-www-form-urlencoded

关键请求参数:

参数 来源 说明
appId 业务方配置 绑定具体业务,从前端 JS 中提取,固定值
type 固定 1 表示滑动验证
version 固定 SDK 版本号
pn 固定 业务包名,前端 JS 中可查
os 固定 3 表示 Web 环境
sdkName 固定 SDK 标识
timestamp 本地生成 毫秒时间戳
nonce 本地生成 与 timestamp 相同
phone 固定 示例账号占位
sign 本地计算 各参数按字母序拼接后 MD5,详见第四节

响应示例:

json 复制代码
{
  "error": 0,
  "msg": "成功",
  "data": {
    "captchaId": "xxx",
    "token": "yyy",
    "bg": ["https://xxx.360.cn/xxx/<bg_id>.png"],
    "front": ["https://xxx.360.cn/xxx/<slice_id>.png"]
  }
}

背景图 URL 路径末段的文件名(不含扩展名)即为用于计算列置换表的 bg_id

3.2 check 接口

请求:

复制代码
POST https://captcha.jiagu.360.cn/api/v3/check
Content-Type: application/x-www-form-urlencoded

关键请求参数:

参数 来源 说明
captchaId auth 响应 本次验证会话 ID
token auth 响应 会话凭证,原样透传
length 本地计算 滑动距离(300px 归一化坐标),核心识别结果
width 固定 300,与服务端约定的归一化宽度
version 固定 SDK 版本号
report 本地加密生成 核心参数,见第五节
tracking 固定 [object Object](前端遗留值)

四、签名算法(sign)

auth 请求中的 sign 字段用于防篡改校验,生成规则为:

  1. 将所有请求参数(除 sign 本身)按参数名字母序 拼接,格式为 key1value1key2value2...,无分隔符
  2. 对拼接字符串执行 MD5 得到 32 位小写十六进制

注意:timestampnonce 虽然同值,但两者均参与拼接,且按字母序 nt 之前。


五、图片列乱序与还原

5.1 乱序机制

服务端下发的背景图并非正常图片,而是将原始图按 17px 宽分成 32 列后打乱顺序 拼接而成(原图尺寸 544×284px,17×32=544)。还原需要先根据 bg_id 计算列置换表。

5.2 置换表计算

置换表算法以图片 ID 字符串为输入,逐字符生成一个 0~31 的无重复排列:

复制代码
对于 i in range(32):
    val = ord(bg_id[i]) XOR 0x20
    val = val % 32
    若 val 已被占用,则 val = (val + 1) % 32(线性探测)
    记录 val,标记为已用

该算法本质是一个基于字符编码的哈希置换 + 线性探测冲突解决,确保每个位置只被映射一次。

5.3 图片还原

得到置换表 col_order(长度 32 的列表)后:

  • 对于原乱序图的第 i 列(x = i×17),将其粘贴到还原图的第 col_order[i] 列位置(x = col_order[i]×17)
python 复制代码
for index, target_pos in enumerate(col_order):
    x = index * 17
    col = bg_img.crop((x, 0, x + 17, 284))
    recover_img.paste(col, (target_pos * 17, 0))

注意 :图片下载时需禁用 HTTP 缓存(添加 Cache-Control: no-cache 请求头并给 URL 附加随机时间戳参数),否则 CDN 可能返回上一次请求的旧图,导致每次识别结果相同但验证均失败。


六、图像识别------多策略融合缺口检测

识别目标:在还原后的背景图上找到滑块拼图缺口的 x 坐标。

6.1 四种检测策略

策略 核心方法 特点
edge Canny 边缘检测 + TM_CCOEFF_NORMED 模板匹配 对边缘轮廓敏感,受纹理噪声影响
alpha_mask 提取滑块透明通道作为掩码后匹配 利用 RGBA 信息精准定位,受滑块形状影响
multi_scale 以 0.9/1.0/1.1 三个缩放比例逐一匹配取最优 对轻微缩放有鲁棒性,置信度相对可靠
gradient Sobel 水平梯度垂直累加,找梯度峰值列 不依赖滑块图,纯背景分析,精度最低

6.2 结果融合策略

四种策略独立执行,每个返回 (x坐标, 置信度, 策略名) 三元组,再通过以下逻辑取最优结果:

复制代码
1. 若任一策略置信度 > 0.7,直接采用
2. 过滤 x < 40px 的结果(缺口不可能在最左侧)
3. 遍历两两组合,若差值 ≤ 30px 则认为是同一簇:
   - 用置信度加权计算簇中心
   - 取总置信度最高的簇
4. 若无聚类,排除 gradient 策略后对剩余结果做置信度加权平均

gradient 策略置信度动态计算(峰值/均值比值),不再固定为 0.5,避免其以固定权重干扰聚类。

6.3 距离归一化

识别得到的 distance 为原图坐标(544px 宽度下),提交前需换算到服务端约定的 300px 宽度:

python 复制代码
compressed_distance = round(distance * 300 / 544)

七、轨迹生成

check 接口要求提交滑动轨迹,格式为按序编号的字典列表:

json 复制代码
[{"0": {"t": 1744812345000, "y": 200.0}}, {"1": {"t": 1744812345015, "y": 200.3}}, ...]

其中 t 为毫秒绝对时间戳,y 为鼠标纵坐标。轨迹生成采用物理加速模型模拟拟人滑动:

阶段 逻辑
起步阶段(0~70% 目标距离) 加速度 1.5~3,快速提速
减速阶段(70%~终点) 加速度 -1~0.5,模拟制动
过冲(overshoot) 超出目标 3~8px,再缓慢回退
Y 轴抖动 每步随机 ±1.5px(前进)、±0.3px(回退)
帧间隔 随机 1020ms(前进)、2040ms(回退)

八、RSA 加密(report 参数)

8.1 report 结构

复制代码
report = RSA_Encrypt(str(track)) + MD5(captchaId + token)

即:轨迹字符串经 RSA 加密后的结果,直接拼接会话完整性哈希(无分隔符)。

8.2 RSA 分块加密

使用 RSA PKCS1_v1_5,公钥通过模数(hex)+ 固定指数(65537)构造,模数可通过调试 SDK JS 获取。

由于轨迹字符串远超单次 RSA 加密的最大明文长度(密钥长度 - 11 字节),需要分块加密。分块边界由 SDK 自定义算法决定:

复制代码
维护累计字节数 r,逐字符累加 UTF-8 字节大小:
当 (r % 117 >= 114 或 r % 117 == 0) 且 (r - 上次分块位置 >= 114) 时切割

每块独立加密为 hex 字符串,最终所有块 hex 拼接后做 Base64 编码:

python 复制代码
combined_hex = ''.join(block.hex() for block in encrypted_blocks)
encrypted_track = base64.b64encode(bytes.fromhex(combined_hex)).decode()

公钥模数(modulus)在 SDK JS 中以 hex 字符串形式存在,建议通过 Hook PKCS1_v1_5.encrypt 在运行时动态确认其与当前版本的对应关系。


九、完整请求流程概述

步骤 动作 说明
1 构造 auth 参数 生成 timestamp/nonce,计算 sign(MD5 字母序拼接)
2 调用 auth 接口 获取 captchaId、token、bg URL、front URL
3 计算列置换表 取 bg URL 末段文件名,逐字符 XOR+取模+线性探测冲突解决
4 下载图片 禁用 HTTP 缓存,确保每次下载最新图片
5 还原背景图 按置换表重组 32 列(每列 17px)
6 识别缺口 四策略独立执行,聚类融合取最优,换算为 300px 坐标
7 生成轨迹 物理加速模型 + 过冲 + 随机抖动
8 加密构造 report RSA 分块加密轨迹(自定义切块) + MD5 会话哈希
9 调用 check 接口 携带 length、report 等参数,解析返回结果

限流注意:auth/check 接口对请求频率有限制,频繁请求会返回 HTTP 403。建议每次请求前随机等待 1~3 秒,遇 403 冷却 10~20 秒后再重试。


十、关键知识点总结

知识点 详情
图片乱序机制 按 17px 列宽分 32 列打乱,基于图片 ID 字符串通过 XOR+取模+线性探测生成置换表
缺口识别 OpenCV 四策略(边缘/透明通道/多尺度/梯度)并行,聚类+置信度加权融合
距离归一化 原图 544px → 压缩 300px,需等比换算再提交
RSA 加密 PKCS1_v1_5,自定义分块边界(117 字节周期),分块 hex 拼接后 Base64
report 结构 Base64(RSA分块加密轨迹) + MD5(captchaId+token)(直接拼接)
签名算法 参数字母序拼接后 MD5,无需密钥
HTTP 缓存陷阱 图片请求必须禁用缓存,否则 CDN 可能返回旧图导致识别结果固定
轨迹格式 [{"index": {"t": ms时间戳, "y": 纵坐标}}, ...] 的编号字典列表

十一、与极验 GT4 的横向对比

对比维度 360 天御 极验 GT4
加密算法 RSA PKCS1_v1_5,输出 Base64 AES-CBC + RSA,输出 hex
图片保护 列乱序(32列×17px,基于文件名置换) 无乱序,标准图片直接下载
参数结构 length + report(track+MD5拼接) 单一 w 参数(AES加密数据+RSA加密密钥)
工作量证明 无 PoW 有 PoW(pow_detail 动态下发,支持 bits>0 碰撞)
签名机制 参数字母序 MD5 无额外签名
图像识别库 OpenCV 多策略 ddddocr(更简便)
图片分辨率 原图 544px → 需归一化到 300px 标准分辨率,无需归一化
JSONP 解析 无,标准 JSON 需动态定位括号解析
JS 混淆程度 中等,关键逻辑可读 gt4.js 基本可读

十二、依赖安装

bash 复制代码
pip install requests pycryptodome opencv-python pillow numpy

本文技术仅供安全研究与学习,切勿用于任何未授权系统,违者后果自负。

相关推荐
木斯佳15 天前
HarmonyOS 6实战:图片验证码迁移报错的复盘思考
harmonyos·验证码·人机校验
小曹要微笑1 个月前
WinForms 验证码类的实现
c#·验证码·winform·验证码类
槐序十七^2 个月前
某CSDN文字点选算法分析
js逆向·哈希算法·验证码·python爬虫·pyhon·文字点选验证码
shizhenshide3 个月前
社交媒体自动化:批量注册/发帖的验证码难题一站式解决
自动化·php·媒体·验证码·ezcaptcha
Bright Data3 个月前
Facebook 验证码解决方案
验证码·facebook
shizhenshide3 个月前
物联网(IoT)设备如何应对验证码?探讨无头浏览器与协议级解决方案
java·struts·microsoft·验证码·ezcaptcha
shizhenshide4 个月前
“绕过”与“破解”的成本账:自行研发、购买API与外包打码的性价比全分析
人工智能·验证码·recaptcha·ezcaptcha·recaptcha v2
shizhenshide4 个月前
隐形杀手:无感验证(Invisible CAPTCHA)的工作原理与存在性检测方法
microsoft·验证码·ezcaptcha
gc_22994 个月前
Ape.Volo项目源码学习(3:生成验证码)
验证码·ape.volo