在家隔离2个多月的时间里,看了很多关于滑动验证码的破解技术博客,大多使用 Selenium、Webdriver 等技术破解的,我也尝试了破解xxxx网站,效率蛮低的,满足不了实时数据更新的需求,然后看到一些高级爬虫前辈直接通过解密 JavaScript 参数破解。效率高并且成功率是100%,但是难度非常的大。
目前,对于这一类的滑动验证码,网上常见的一个破解方法就是根据完整图片和缺口图片的像素差来计算缺口的位置,然后使用 Selenium 自动化测试工具,模拟人手动拖动滑块的过程。这种方法实现较为简单,因为是模拟人去滑动,滑动的轨迹很不好把握,很容易被极验检测到我们使用的是自动化软件,从而导致滑动操作失败;其次是每一次启动都需要驱动浏览器,登录耗时较长,这对于实时性要求较高的数据采集任务来说,是无法满足需求的。
高级爬虫的厉害之处是走的逆向解析JS代码破解:死磕 JavaScript 代码,破解每个请求中的加密参数,之后在程序中发送请求得到正确响应。 这是最直接且最高效的方式,它无需等待浏览器对页面进行渲染,只要解出加密的请求参数,发送请求获取响应即可。用户在浏览器中的操作,如点击验证码、拖动滑块等动作,最终都会转化为请求发送到服务端(全部都是POST请求),服务端对请求参数进行合法性校验,并响应结果。
为什么说很难呢,一是因为我并非从事前端开发工作,对于 JavaScript 代码的调用栈分析不如前端同学熟练;二是因为极验的 JavaScript 代码实在混淆得特别难懂,如何从上万行混淆的 JavaScript 代码中抽离出关键的加密代码,可以相信想象下里面的工作量。可以毫无夸张地说,没有足够的毅力和耐心,很难实现破解。
动手破解
接下来我会大致描述整个破解流程,对于过于细节化的东西,就不在这里瞎丢丢了。
1. 请求参数分析
我以最终的登录方法作为分析入口。输入一个错误的账号密码,然后点击滑动并拖动到正确的位置。此后页面会提示“账户名或密码错误!”。观察浏览器 Network 栏,其实登录这个动作是发出了 Name 为 accLoginPC.do 这个请求。
请求的 URL 是:https://xxx.xxx/webapi/accLoginPC.do (敏感的URL)。
请求参数 Form Data 有多个,包括:appId、loginName、loginPwd、geetest_challenge 等。可以看到,密码被加密成 CN-S513... 这一长段,另外还有三个以 geetest_ 开头的加密参数,分别是:
- geetest_challenge: 102f7d723ad76e387ad6000f87ff91f8j3
- geetest_validate: 651ecdf62cb1e940e5ea999b6af7fc10
- geetest_seccode: 651ecdf62cb1e940e5ea999b6af7fc10|jordan
从参数命名上,我们能够很清晰地看出,这是极验滑动验证码的加密参数。也即是说,我们点击验证码,拖动滑块这些动作,最终转换为这三个加密参数。我们的主要工作,也在于破解这三个参数。细心的同学可能发现了,其中 geetest_validate 与 geetest_seccode 参数基本相同,只不过 geetest_seccode 多了 |jordan 的字符串后缀。最主要的工作就是解出 challenge/validate 两个参数。
对于其他非极验加密参数,如 loginPwd、jtSafeKey、token 等,均属于XX官网自身的加密逻辑,破解难度不大,这里我们主要关注的是极验参数的破解。
我们再往上找,发现了 ajax.php? 这个请求,这个请求里的响应信息是一个类似 json 串的东西,里面包着 validate 参数。震惊,这不就是我们前文的 geetest_validate 参数吗?
观察其请求参数,发现是 gt、challenge、lang、w 和 callback。其中 w 加密成了一长串。