本文通过自动化查询域名或公司的备案信息,来演示其中图片滑动验证码的破解方式,以此来思考验证码的安全性问题,思考如何设计出安全性更高的验证码。
注意:破解验证码进行网络内容抓取可能是一种违规行为,可以以此进行验证码安全性分析研究,不要用于恶意活动。
什么是验证码
现在的 web 应用,在进行重要操作时,比如用户登录、信息修改、重要信息查询等,往往都需要验证码。验证码的主要目的是防止自动化程序或机器人在网站上执行恶意操作。
图片形式的验证码是最常用的一种形式,下面列出几种常见的图片形式验证码:
- 字母验证码:字母混合数字的组合,要求用户根据图片中的字母和数字进行识别并输入。
- 数字验证码:由一组数字组成,要求用户根据图片中的数字进行识别并输入。
- 滑动验证码:用户需要按照提示拖动图片中的滑块或者完成一些简单的拼图等操作来完成验证。
- 变形文字验证码:字母或数字倒立或者扭曲的形式,要求用户对倒立或扭曲的字母或数字进行识别并输入。
- 算术验证码:要求用户在图片中计算出两个数字的和或差,并输入正确的结果。
- 图片识别验证码:用户需要根据给定的提示,从一组图片中选择符合提示的图片,例如选择带有车辆或路灯的图片等。
这里要注意的是,虽然同一个种类的验证码的前端表现可能相同,但是背后实现的方式可能不同。
自动破解验证码
破解验证码是通过各种技术手段来自动识别或者绕过验证码验证,尽管验证码的设计者在不断改进验证码的安全性,但是验证码破解方式也在不断创新,这使得验证码的安全性不断受到挑战。
通过上面的介绍,我们知道验证码的种类很多,因此不同种类验证码的破解方式也不相同,而且由于实现方式的不同,往往需要具体情况具体分析。
图片验证码破解的总体思路是模拟用户的操作进行验证码验证。
举例:
- 针对图片内容识别类验证码,可以识别图片中的内容进行自动验证,这里可能要利用机器学习或图像处理技术来识别内容。
- 针对图片滑动、旋转类验证码,可以模拟用户操作,如计算图片要滑动的距离,要旋转的角度,模拟人类鼠标操作时的轨迹曲线等。
- 或者直接人力破解,针对有价值的目标,也有聘请人工智能平台或工人手动识别并解决验证码的情况。
本文介绍图片滑动验证码的破解方式,这是一种破解起来相对简单的验证码。
图片滑动验证码
图片滑动验证码是一种比较常见的验证码,一般都是通过滑动图片的一部分进行图片拼图,以进行操作验证。示意图像下面这样。
从用户体验来看,用户只需要使用鼠标拖动滑块到指定位置,如果位置正确,则通过验证。这是一种十分好用的验证方式,相比输入形式的验证码,省去了用户键盘的输入过程。
这类验证码的实现过程一般如下:
- 服务端准备图片若干个。
- 用户请求获取图片验证码,服务端随机选取一个图片作为验证码大图,复制指定形状的一小部分图片内容作为滑块。
- 记录复制的滑块位置,响应大图,滑块图给前端。
- 用户拖动滑块拼图,把滑动的位置信息发送给服务器。
- 服务器验证滑动位置是否和记录的相近,允许一定像素的误差,验证是否通过。
具体案例分析
我们通过分析一个备案查询网站来演示滑动验证码的破解,目前网站的操作流程是输入一个域名或者公司信息,点击查询,弹出图片滑动验证码,用户滑动图片验证码进行验证,验证通过则返回查询信息。
本文仅用于学习交流,不可用于商业及非法用途
我们先通过查看网站的网络请求情况,分析操作背后的流程(以下的操作并不是一次完成,所以截图中的某些值可能对不上)。
访问网站
访问网站 https://beian.miit.gov.cn,发现自动请求了 auth 接口,在请求时携带了两个参数,截图如下。
其中 timeStamp 很明显是一个毫秒时间戳,那么 authKey 值是怎么来的呢?通过分析网站 javascript 代码,可以发现它的生成规则为 MD5('test'+test'+timeStamp)
,分析截图如下。
请求后获取到了一个 bussiness 信息,作为后续请求的认证 token。
获取验证码
在网站上搜索一个域名,弹出图片验证码信息,再次查看请求信息。发现发起了一个 POST
请求,并且在请求头中携带了 Token
信息用于认证,这个 Token
就是第一步获取到的 bussiness
。
响应信息是 base64 编码后的图片,一个是大图,一个是用于滑动的方块,其中的 uuid
可以认为是图片 id,在图片验证时需要传给服务器。
// 下面的响应信息,为了方便查看,我删去了部分内容,所以不要直接解码,解不出来的。
{
"code": 200,
"msg": "操作成功",
"params": {
"smallImage": "/9j/4AAQSkZJRgABAQEAYABgAAD/2wBDAA0JCgsKCxxxxxxxxxxxxxx",
"bigImage": "/9j/4AAQSkZJRgABAQEAYABgAAD/2wBDAA0JCgsKCA0lFAj/2Qxxxxxxxxxxx",
"uuid": "87db2dbb-4c1d-4633-a624-0045305e61e3",
"height": "81"
},
"success": true
}
如果我们拿 bigImage
内容进行 Base64 转图片,可以看到验证码大图。
验证码校验
我们滑动图片验证码到准确位置,这时会发起验证请求,我拷贝出了这条请求的详细信息。
curl 'https://hlwicpfwc.miit.gov.cn/icpproject_query/api/image/checkImage' \
-H 'Accept: application/json, text/plain, */*' \
-H 'Accept-Language: zh-CN,zh;q=0.9' \
-H 'Connection: keep-alive' \
-H 'Content-Type: application/json' \
-H 'Cookie: __jsluid_s=ef117b2a4d0d504c0f729f605e22bea7' \
-H 'Origin: https://beian.miit.gov.cn' \
-H 'Referer: https://beian.miit.gov.cn/' \
-H 'Sec-Fetch-Dest: empty' \
-H 'Sec-Fetch-Mode: cors' \
-H 'Sec-Fetch-Site: same-site' \
-H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36' \
-H 'sec-ch-ua: "Not.A/Brand";v="8", "Chromium";v="114", "Google Chrome";v="114"' \
-H 'sec-ch-ua-mobile: ?0' \
-H 'sec-ch-ua-platform: "macOS"' \
-H 'token: eyJ0eXBlIjoxLCJ1IjoiMDk4ZjZiY2Q0NjIxZDM3M2NhZGU0ZTgzMjYyN2I0ZjYiLCJzIjoxNjg5MDg3OTIxMTEwLCJlIjoxNjg5MDg4NDAxMTEwfQ.RdP9am6518e4z9EsrFQz18ZQjwvhgserJ5y2ZVx7rqo' \
--data-raw '{"key":"6af2c1bb-47a4-479d-a9f1-1ab17f86214e","value":"320"}' \
--compressed
从中可以发现,依旧在请求头中携带了 Token
字段。同时请求体携带了 key
和 value
两个字段,其中 key
就是上一步获取到的图片的 uuid
,value
则是滑动验证码滑动的距离。320 也就是表示滑动了 320 个像素位置进行了拼图。
验证通过后得到响应信息,其中 params
是验证后得到的可以用于请求验证的值。
{
"code": 200,
"msg": "操作成功",
"params": "eyJ0eXBlIjozLCJleHREYXRhIjp7InZhZnljb2RlX2ltYWdlX2tleSI6IjZhZjJjMWJiLTQ3YTQtNDc5ZC1hOWYxLTFhYjE3Zjg2MjE0ZSJ9LCJlIjoxNjg5MDg4NDQ0MTM2fQ.cYPpQya1KiWZgC3T8ZNr9cWAM2aTHDtFUpzPIO-sMhQ",
"success": true
}
信息返回
验证通过后会自动请求域名备案信息查询接口,下面是复制出的请求信息。
curl 'https://hlwicpfwc.miit.gov.cn/icpproject_query/api/icpAbbreviateInfo/queryByCondition' \
-H 'Accept: application/json, text/plain, */*' \
-H 'Accept-Language: zh-CN,zh;q=0.9' \
-H 'Connection: keep-alive' \
-H 'Content-Type: application/json' \
-H 'Cookie: __jsluid_s=ef117b2a4d0d504c0f729f605e22bea7' \
-H 'Origin: https://beian.miit.gov.cn' \
-H 'Referer: https://beian.miit.gov.cn/' \
-H 'Sec-Fetch-Dest: empty' \
-H 'Sec-Fetch-Mode: cors' \
-H 'Sec-Fetch-Site: same-site' \
-H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36' \
-H 'sec-ch-ua: "Not.A/Brand";v="8", "Chromium";v="114", "Google Chrome";v="114"' \
-H 'sec-ch-ua-mobile: ?0' \
-H 'sec-ch-ua-platform: "macOS"' \
-H 'sign: eyJ0eXBlIjozLCJleHREYXRhIjp7InZhZnljb2RlX2ltYWdlX2tleSI6IjZhZjJjMWJiLTQ3YTQtNDc5ZC1hOWYxLTFhYjE3Zjg2MjE0ZSJ9LCJlIjoxNjg5MDg4NDQ0MTM2fQ.cYPpQya1KiWZgC3T8ZNr9cWAM2aTHDtFUpzPIO-sMhQ' \
-H 'token: eyJ0eXBlIjoxLCJ1IjoiMDk4ZjZiY2Q0NjIxZDM3M2NhZGU0ZTgzMjYyN2I0ZjYiLCJzIjoxNjg5MDg3OTIxMTEwLCJlIjoxNjg5MDg4NDAxMTEwfQ.RdP9am6518e4z9EsrFQz18ZQjwvhgserJ5y2ZVx7rqo' \
-H 'uuid: 6af2c1bb-47a4-479d-a9f1-1ab17f86214e' \
--data-raw '{"pageNum":"","pageSize":"","unitName":"qq.com"}' \
--compressed
其中 sign
是图片校验通过后的验证信息。token
是第一步获取到的验证信息,uuid
是验证码唯一标识。请求参数中的 unitName
值是要查询的域名 qq.com
。
请求后成功响应了域名备案信息,至此,我们完整的分析了备案信息查询的全过程。
{
"code": 200,
"msg": "操作成功",
"params": {
"endRow": 0,
"firstPage": 1,
"hasNextPage": false,
"hasPreviousPage": false,
"isFirstPage": true,
"isLastPage": true,
"lastPage": 1,
"list": [
{
"contentTypeName": "宗教、宗教、出版、文化、新闻、文化、文化、文化、新闻、宗教",
"domain": "qq.com",
"domainId": 190000203203,
"leaderName": "",
"limitAccess": "否",
"mainId": 547280,
"mainLicence": "粤B2-20090059",
"natureName": "企业",
"serviceId": 4134047,
"serviceLicence": "粤B2-20090059-5",
"unitName": "深圳市腾讯计算机系统有限公司",
"updateRecordTime": "2023-07-10 11:58:09"
}
],
"navigatePages": 8,
"navigatepageNums": [
1
],
"nextPage": 1,
"orderBy": "",
"pageNum": 1,
"pageSize": 10,
"pages": 1,
"prePage": 1,
"size": 1,
"startRow": 0,
"total": 1
},
"success": true
}
图片滑动验证码破解
如何破解验证码呢,通过上面的具体案例分析,我们发现其实在访问网站获取 Token
阶段,获取验证码阶段,以及最后的信息返回阶段,都是比较简单的 HTTP 请求,只要能构造相应的 HTTP 请求,并携带具体的请求头信息,就可以模拟请求了。
比较不好办的是验证码校验这个阶段,因为要计算验证码的滑动距离,这里需要涉及到图像处理知识,那么该怎么办呢?
验证码图片分析
我们获取几张验证图片观察,明显看到在要滑动的目标区域有被阴影覆盖,那么这一部分的 RGB 颜色就有所变化,一个正常的图片很少有这种矩形方块的颜色突变。
灰度图片
通过上面的分析,我们发现色彩其实并不重要,图片的灰度变化(或者叫亮度变化)比较重要,因为目标区域有被灰色覆盖。会产生一个矩形突变,那么我们可以把图片转换成灰度图片,这样更有利于观察。
准备验证图片一张,对应的 base64 编码如下:
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
我们把这个图片进行解码,然后转换成灰度图片。
其中灰度值通过公式 R * 0.2126 + G * 0.7152 + B * 0.0722
计算得到。
public static void main(String[] args) {
String base64String = "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";
byte[] decodedBytes = Base64.getDecoder().decode(base64String);
try (FileOutputStream fos = new FileOutputStream("image.png")) {
fos.write(decodedBytes);
} catch (IOException e) {
e.printStackTrace();
}
changeImageGray(decodedBytes);
}
public static void changeImageGray(byte[] imgByte) {
try {
// 读取图片
BufferedImage image = ImageIO.read(new ByteArrayInputStream(imgByte));
// 获取图片的宽度和高度
int width = image.getWidth();
int height = image.getHeight();
int[][] lightArray = new int[height][width];
// 遍历图片的像素点,将其转换为黑白
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
// 获取像素点的颜色
Color color = new Color(image.getRGB(x, y));
// 计算灰度值
int gray = Double.valueOf((color.getRed() * 0.2126 + color.getGreen() * 0.7152 + color.getBlue() * 0.0722)).intValue();
// 将像素点的颜色设置为非黑即白
Color newColor = new Color(gray, gray, gray);
image.setRGB(x, y, newColor.getRGB());
}
}
// 保存黑白图片
File output = new File("gray.jpg");
ImageIO.write(image, "jpg", output);
log.info("验证码图片已保存为:{}" ,output.getAbsolutePath());
} catch (Exception e) {
e.printStackTrace();
}
}
这样可以把图片转换成下面的这个样子。
其实这时,如果我们输出图片的每个像素点的灰度矩阵,已经可以发现灰色方块处的灰度特点了。可以很明显的看到灰色方块区域的灰度值变化。
如果你检测这个灰度矩阵,你已经有办法找到灰色区域开始的位置了。
图片二值化
为了更方便的分析,我们可以对图片再次转化,我们可以选取一个阈值,**超过指定阈值的像素点直接转换成白色,低于指定阈值的颜色转换成黑色。**这样更方便后续的分析。
改造代码,添加亮度阈值判断,这里选择 100 作为阈值。
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
// 获取像素点的颜色
Color color = new Color(image.getRGB(x, y));
// 计算灰度值
int gray = Double.valueOf((color.getRed() * 0.2126 + color.getGreen() * 0.7152 + color.getBlue() * 0.0722)).intValue();
// 将像素点的颜色设置为非黑即白
if (gray > 100) {
gray = 255;
} else {
gray = 0;
}
Color newColor = new Color(gray, gray, gray);
image.setRGB(x, y, newColor.getRGB());
}
}
转换后的图片变化如下:
如果我们打印这个二值化后的图片像素矩阵,可以更加清楚的看到灰色矩形区域几乎都是 0 值。
滑动距离计算
对二值化后的图片进行计算,可以非常方便的找到灰色矩形开始的位置,只需判断每个 (x,y)
像素值和前一个像素 (x-1,y)
的值变化情况即可。如果某一列出现大量从 255
变化到 0
的像素,这里很大概率是达到了矩形的第一个边界,这列所在的 x
值就是要移动的距离。
简单的计算方式如下:
// lightArray 存储了二值化后的图片像素信息
// 扫描发现 255->0 变化的最大数量
int maxChangeCount = 0;
// maxChangeCount 对应的列值
int index = 0;
for (int w = 1; w < width; w++) {
int changeCount = 0;
for (int h = 0; h < height; h++) {
if (lightArray[h][w] == 0 && lightArray[h][w - 1] == 255) {
changeCount++;
}
}
if (changeCount > maxChangeCount) {
maxChangeCount = changeCount;
index = w;
}
}
log.info("分析得到验证码坐标值:{}" , index);
针对用于测试的熊猫验证码图片,计算得到滑动距离为 127
,验证图片发现距离也大概是 127px 左右。
至此,图片滑动验证码自动化破解完成。
由于测试的网站并没有加入拖动轨迹的验证,某些滑动验证码会分析鼠标拖动的轨迹来判断是否是人工拖动。
如果我们模拟 HTTP 请求,串起所有的步骤,那么就可以自动化查询域名的备案信息。下面是我的测试(合规原因,完整代码就不贴了,如果需要完整代码可以找我(公众号或微信))。
总结
本文介绍了常见的图片验证码形式,紧接着具体介绍了图片滑动验证码的实现原理,并选择一个网站进行具体的图片滑动验证码验证流程分析,最后介绍如何破解图片滑动验证码,主要是如何计算图片滑动的距离。
一如既往,文章中代码存放在 Github.com/niumoo/javaNotes.
本文 Github.com/niumoo/JavaNotes仓库已经收录。
本文原发于网站:如何破解滑动验证码?
本文原发于公众号:如何破解滑动验证码?