小小滑块可笑可笑-安卓滑块验证码通杀方案研究(1)
前言
通常我们在做自动化任务时候,经常会遇到一些验证码验证。
其中遇到最多的还是滑块验证码,下面我们来单独探讨这个滑块的过程。
一些说明 因为滑块通常是拼图形式 或者是干脆就是从左到右的滑动就行。
这里只重点讨论滑块的滑部分 关于识别滑动位置 需要单独开文章来讲解
图中的例子
逆向抓包拦截方案(好用但不通用)
核心思想就是对验证的页面进行逆向分析,根据上传的包信息。分析出具体滑动的参数,直接伪造一条滑动参数过去。
服务器后台接收参数之后认为你已经滑动成功,代替手动滑过。
但是要做的这一点需要极高的知识储备,需要很多的逆向知识。
优点是很快 很有针对性
缺点是
1.难度大 通常还有很多的参数校验 需要一一破解
2.不够通用也不够灵活 一个新的app或者新的滑块都需要重写全部逻辑
所以我们探讨一种通用的 滑动协议 就是使用自动化的方式代替我们去滑动。
自动化滑动方案(通用但是不够好)
既然讨论的是滑动 当然就是关于如何自动化而不是手动,不然所有讨论都没有意义。
关于自动化 类似的方案有:
1.adb
2.appium 测试框架 等 方案
3.无障碍 类似auto.js 等 方案
现在测试下三种方案的滑动代码
1.adb 滑动代码
adb shell input swipe 250 250 300 300
指的就是从 250,250 滑动到 300,300 坐标 可以多段坐标移动 匀速的
2.appium滑动代码
关于appium 我用的不多,我只能直接从网上抓到一部分代码
http://appium.io/ 文档里关于滑动这一块的:
Android 4.3+: 谷歌的 UiAutomator / UiAutomator2Android 2.3+: 谷歌的 Instrumentation. (通过绑定独立的项目—— Selendroid 提供对 Instrumentation 的支持)
因为appium是基于谷歌的测试框架的 所以逻辑类似:
https://appium.io/docs/en/writing-running-appium/touch-actions/
https://appium.io/docs/en/writing-running-appium/android/android-mobile-gestures/
这是关于点击操作的文档地址
关于滑动手势swipeGesture
的
该手势在给定的元素/区域上执行滑动手势。自Appium v1.19起可用
支持的参数
elementId:要刷卡的元素的ID。如果缺少元素ID,则必须提供滑动边界区域。如果同时提供了元素ID和滑动边界区域,则该区域将被有效忽略。
left:滑动边界区域的左坐标
top:滑动边界区域的顶部坐标
width:滑动边界区域的宽度
height:滑动边界区域的高度
方向:滑动方向。强制值。可接受的值为:up,down,left和right(不区分大小写)
percent:滑动的大小占滑动区域大小的百分比。有效值必须是0..1范围内的浮点数,其中1.0是100%。强制值。
speed:执行此手势的速度,以每秒像素为单位。该值不能为负。默认值为5000 * displayDensity
代码示例:
((JavascriptExecutor) driver).executeScript("mobile: swipeGesture", ImmutableMap.of(
"left", 100, "top", 100, "width", 200, "height", 200,
"direction", "left",
"percent", 0.75
));
同样可以从a点移动到b点 速度也是匀速的。这里额外的有一个传入元素id功能,可以直接对应滑过指定控件,比adb更方便和高效一点。
3.无障碍的滑动代码
直接使用无障碍方式滑动,关于滑动这个动作。无障碍在7.0版本上新增了dispatchGesture
这个动作来来滑动。
具体可以这样写:
Path path1 = new Path();
path1.moveTo(x1, y1);
path1.lineTo(x1, y2);
GestureDescription.Builder builder = new GestureDescription.Builder();
GestureDescription gestureDescription = builder
.addStroke(new GestureDescription.StrokeDescription(path1, 0, 1000))
.build();
service.dispatchGesture(gestureDescription, null, null);
这就从x1滑动到了x2了,甚至可以多家几条path达到控制速度的调整。
int y1 = 800;
int y2 = 1000;
int x1 = 200;
int x2 = 400;
int x3 = 600;
int x4 = 800;
Path path1 = new Path();
path1.moveTo(x1, y1);
path1.lineTo(x1, y2);
Path path2 = new Path();
path2.moveTo(x1, y2);
path2.lineTo(x2, y2);
Path path3 = new Path();
path3.moveTo(x2, y2);
path3.lineTo(x4, y2);
GestureDescription.Builder builder = new GestureDescription.Builder();
GestureDescription gestureDescription = builder
.addStroke(new GestureDescription.StrokeDescription(path1, 1000, 1000))
.addStroke(new GestureDescription.StrokeDescription(path2, 1900, 1000))
.addStroke(new GestureDescription.StrokeDescription(path3, 2800, 1000))
.build();
service.dispatchGesture(gestureDescription, null, null);
三条路径滑动 间隔连上就会变成一个了。但是系统做了限制,最多最多添加10条路径,否则会抛出异常。
测试滑动验证效果
自行编写的滑块验证码
关于这一点 我为了方便快速测试,自己找了一些开源的验证码模块改了改。
通过要求只有一点: 只要用户能从A划到B点末端就算成功
三种方式的测试成功率都很高,因为这种简单的从左滑到右都是秒过的。
至此大功告成,三种方案通杀了安卓客户端的验证码模块(我以为)
第三方平台验证码
这次挑了几个大厂的app 故意跑出来验证码:
尝试直接滑过,结果就是虽然滑倒了指定的地方。但是直接返回了一个大大的失败二字。
这里涉及的app有 快手 闲鱼 小红书等等几大平台。正因为我在做日常的闲鱼爬虫
以及更多数据爬虫的时候会遇上这些烦人的滑块。
验证结果:
快手:失败 100%
闲鱼:失败 100%
小红书:失败 100%
可知所有的app都能轻易的知道我是用自动化方式划过的,而且直接拒绝了这次的滑动验证请求。
分析失败原因和解决思路
失败原因:为何第三方app校验不通过
在分析这个滑动校验原理的过程中,我发现了一个专门做滑动验证的厂商--极验
在他的安全风控里面我找到了一些有用的的信息:
原来这些验证平台不讲武德,直接配合大数据和AI判断了我的滑动轨迹。
这种匀速的滑动根本过不了验证平台的校验。
类似的还有数美 同盾 网易等验证平台
解决方案:如何做出和真人一样的滑动
首先可以认定的就是 那些普通的自动化工具只能做一些非常机械化的滑动,无论是匀速还是加速减速都显得非常的机械化。
这种机械化的速度变化曲线会非常容易针对,只要做个简单的校验就可以拦住了。
所以我们追求一个更加颗粒度的滑动方案,不是平滑的滑动。也不是一段一段的滑动,而是精确度粒度达到一像素一像素的程度才行。
具体的策略如下:
- 生成符合规则的路径曲线 模仿人类的速度 抖动等参数
- 使用像素级别的颗粒度的滑动控制工具滑动界面滑块
- 调整 适配 再生成曲线 再调整 再适配 提高成功率到满意程度
总结
关于滑动验证码的探究方案到这里了,至于如何做出像素级别得到滑动看下下篇文章的分解。