GeeTest滑块验证码通过机器学习检查鼠标行为轨迹,识别人工或机器行为。
online在线验证的流程,目前最全面的分析文档详见 https://zhuanlan.zhihu.com/windev 。
online模式的验证流程,网站后台与GeeTest后台 http://api.geetest.com 进行通讯验证。浏览器前端仅做数据采集和简单加密传输。
offline模式的离线验证,网站后台自行验证,GeeTest后台 http://static.geetest.com 仅提供滑块验证码图片下载功能。浏览器前端做数据采集和本地验证。
在安全性上,online模式相对非常可靠,offline模式仅仅是障眼法。
1. 测试网站
以国家企业信用信息公示系统为例:
主站使用geetest 5.10.10 online 在线验证模式。各省市站点使用的版本和模块略有差异。
geetest offline 5.9.0
- 上海
- 河北
- 内蒙古
- 辽宁
- 福建
- 山东
- 广东
- 海南
- 湖北
- 湖南
- 四川
- 云南
- 西藏
- 青海
- 宁夏
geetest offline 5.10.10
- 贵州
- 陕西
2. offline模式验证流程
以上海站点为例 http://sh.gsxt.gov.cn
2.1 GET 首页 http://sh.gsxt.gov.cn/notice/
返回HTML页面,解析得到session.token。
2.2 GET register http://sh.gsxt.gov.cn/notice/pc-geetest/register
返回JSON数据
{
"success":0,
"gt":"39134c54afef1e0b19228627406614e9",
"challenge":"d2ddea18f00665ce8623e36bd4e3c7c543"
}
success = 0 表示启用 offline 验证模式。
2.3 POST http://sh.gsxt.gov.cn/notice/security/verify_ip
返回200 True,表示成功。
2.4 POST http://sh.gsxt.gov.cn/notice/security/verify_keyword
返回200 True,表示成功。
2.5 POST http://sh.gsxt.gov.cn/notice/pc-geetest/validate
上传滑块验证码的本地验证结果数据,简称validate。返回JSON数据
{
"status":"success",
"version":"3.3.0"
}
offline模式,后台根本不知道浏览器使用哪张滑块验证码图片,只知道浏览器上传了验证结果的数据。所以完全可以省略下载验证码图片,进行图像识别,计算滑块移动位置,模拟鼠标滑动轨迹这些步骤。
验证数据的格式
例如:1517aab3f_51aa460f_75555a6a38,其中以_分隔的3段数据是由geetest.5.x.x.js中的distance, rand0, rand1加密混淆得到。
具体加密过程分析详见 寻找阿登高地——爬虫工程师如何绕过验证码 。
其实不用关心加密算法的实现细节,只需找到JavaScript调用入口,传入参数执行即可:
function userresponse(a, b) {
for (var c = b.slice(32), d = [], e = 0; e < c.length; e++) {
var f = c.charCodeAt(e);
d[e] = f > 57 ? f - 87 : f - 48
}
c = 36 * d[0] + d[1];
var g = Math.round(a) + c; b = b.slice(0, 32);
var h, i = [ [], [], [], [], [] ], j = {}, k = 0; e = 0;
for (var l = b.length; e < l; e++)
h = b.charAt(e), j[h] || (j[h] = 1, i[k].push(h), k++, k = 5 == k ? 0 : k);
for (var m, n = g, o = 4, p = "", q = [1, 2, 5, 10, 50]; n > 0;)
n - q[o] >= 0 ? (m = parseInt(Math.random() * i[o].length, 10), p += i[o][m], n -= q[o]) : (i.splice(o, 1), q.splice(o, 1), o -= 1);
return p
}
3个参数的正确生成
distance,rand0,rand1,这3个参数都是随机生成,但是如果写代码直接随机生成,会发现验证成功率不高,那么这3个参数之间存在什么隐藏关联关系?后台是如何校验这3个随机数的正确性?
其实它们之间存在什么关系不重要,重要的是能够成功通过验证。
只需人工采样N次,构造足够的样本数组,每次随机选取1个,调用JavaScript加密方法,得到验证数据即可。
2.6 POST http://sh.gsxt.gov.cn/notice/search/ent_info_list
上传session.token(步骤1获得),challenge(步骤2获得),validate(步骤5计算),keyword(查询关键字),返回HTML页面,解析DOM结构,即可获得查询结果和session.token的更新(用于下一次查询)。
3. Demo Source Code
https://github.com/9468305/python-script/tree/master/geetest_offline
Python 3.6 Install:
pip install requests # HTTP Request库
pip install PyExecJS # Python调用JavaScript, 配合node.js更佳
pip install beautifulsoup4 # 解析HTML页面
Demo:
python ./geetest_offline.py
python ./geetest_offline_nm.py
Source Code:
geetest_offline.py for 上海,河北。
geetest_offline_nm.py for 内蒙古, HTTP Request&Response 略有不同。
备注:
GeeTest Offline V6.0.0 与V5.10.10类似,加密方式略有不同,但验证流程和结果相同,因此该方法依然可以正常使用。