当前位置: 首页 > news >正文

掘金滑块验证码安全升级,继续破解

去年发过一篇文章,《使用前端技术破解掘金滑块验证码》,我很佩服掘金官方的气度,不但允许我发布这篇文章,还同步发到了官方公众号。最近发现掘金的滑块验证码升级了,也许是我那篇文章起到了一些作用,逼迫官方加强了安全性,这是一个非常好的现象。

不过,这并不是终点,我们还是可以继续破解。验证码的安全性是在用户体验和安全性之间的一个平衡,如果安全性太高,用户体验就会变差,如果用户体验太好,安全性就会变差。掘金的滑块验证码是一个很好的例子,它的安全性和用户体验之间的平衡做得非常好,并且我们破解的难度体验也非常好。 😄

本次升级的内容

掘金的滑块验证码升级了,主要有以下几个方面的改进:

  1. 首先验证码不再是掘金自己的验证码了,而是使用了字节的校验服务,可以看到弹窗是一个 iframe,并且域名是 bytedance.com

我们都知道掘金被字节收购了,可以猜测验证码的升级是字节跳动的团队做的。

  1. 验证码的图形不再是拼图,而是随机的不同形状,比如爱心、六角星、圆环、月亮、盾牌等。
  2. 增加了干扰缺口,主要是大小或旋转这种操作。

下面看一下改版后的滑块验证码:

我在文章的评论区看到了一些关于这次升级或相关的讨论:

本文将继续破解这次升级后的滑块验证码,看看这次升级对破解的难度有多大影响,如果你还没有了解过如何破解滑块验证码,请先看我之前的文章。

iframe

这次升级,整个滑块都掉用的是外部链接,使用 iframe 呈现,那么在 puppeteer 中如何处理呢?

await page.waitForSelector('iframe');
const elementHandle = await page.$('iframe');
const frame = await elementHandle.contentFrame();

实际上,我们只需要等待 iframe 加载完成,然后获取 iframe 的内容即可。

Frame 对象和 Page 对象有很多相似的方法,比如 frame.$frame.evaluate 等,我们可以直接使用这些方法来操作 iframe 中的元素。

验证码的识别

上一篇文章采用比较简单的判断方式,当时缺口处有明显的白边,所以只需要找到这个白边即可。

但是本次升级后,缺口不再是白边,而是阴影的效果,并且缺口的形状也不再是拼图,大概率都是曲线的边,所以再判断缺口的方式就不再适用了。

现在我们可以采用一种新的方式,通过对比滑块图片和缺口区域的像素值相似程度来判断缺口位置。

首先还是二值化处理,将图片转换为黑白两色:

可以看到左侧缺口和右侧缺口非常相似,只是做了一点旋转作为干扰。

再看一下,iframe 中还有一个很重要的东西,就是校验的图片:


它是一个 png 图片,所以我们可以把它也转换成二值化,简单的方式就是将透明色转换为白色,非透明色转换为黑色,如果想提高识别精度,可以与背景图一样,通过灰度、二值化的转换方式。

// 获取缺口图像
const captchaVerifyImage = document.querySelector('#captcha-verify_img_slide',
) as HTMLImageElement;
// 创建一个画布,将 image 转换成canvas
const captchaCanvas = document.createElement('canvas');
captchaCanvas.width = captchaVerifyImage.width;
captchaCanvas.height = captchaVerifyImage.height;
const captchaCtx = captchaCanvas.getContext('2d');
captchaCtx.drawImage(captchaVerifyImage,0,0,captchaVerifyImage.width,captchaVerifyImage.height,
);
const captchaImageData = captchaCtx.getImageData(0,0,captchaVerifyImage.width,captchaVerifyImage.height,
);
// 将像素数据转换为二维数组,同样处理灰度、二值化,将像素点转换为0(黑色)或1(白色)
const captchaData: number[][] = [];
for (let h = 0; h < captchaVerifyImage.height; h++) {captchaData.push([]);for (let w = 0; w < captchaVerifyImage.width; w++) {const index = (h * captchaVerifyImage.width + w) * 4;const r = captchaImageData.data[index] * 0.2126;const g = captchaImageData.data[index + 1] * 0.7152;const b = captchaImageData.data[index + 2] * 0.0722;if (r + g + b > 30) {captchaData[h].push(0);} else {captchaData[h].push(1);}}
}

为了对比图形的相似度,二值化后的数据我们页采用二维数组的方式存储,这样可以方便的对比两个图形的相似度。

如果想观测二值化后的真是效果,可以把二位数组转换为颜色,并覆盖到原图上:

// 通过 captchaData 0 黑色 或 1 白色 的值,绘制到 canvas 上,查看效果
for (let h = 0; h < captchaVerifyImage.height; h++) {for (let w = 0; w < captchaVerifyImage.width; w++) {captchaCtx.fillStyle =captchaData[h][w] == 1 ? 'rgba(0,0,0,0)' : 'black';captchaCtx.fillRect(w, h, 1, 1);}
}
captchaVerifyImage.src = captchaCanvas.toDataURL();

数据拿到后,我们可以开始对比两个图形的相似度,这里就采用非常简单的对比方式,从左向右,逐个像素点对比,横向每个图形的像素一致的点数量纪录下来,然后取最大值,这个最大值就是缺口的位置。

这里我们先优化一下要对比的数据,我们只需要对比缺口的顶部到底部这段的数据,截取这一段,可以减少对比的性能消耗。

// 获取captchaVerifyImage 相对于 .verify-image 的偏移量
const captchaVerifyImageBox = captchaVerifyImage.getBoundingClientRect();
const captchaVerifyImageTop = captchaVerifyImageBox.top;
// 获取缺口图像的位置
const imageBox = image.getBoundingClientRect();
const imageTop = imageBox.top;
// 计算缺口图像的位置,top 向上取整,bottom 向下取整
const top = Math.floor(captchaVerifyImageTop - imageTop);
// data 截取从 top 列到 top + image.height 列的数据
const sliceData = data.slice(top, top + image.height);

然后循环对比两个图形的像素点,计算相似度:

// 循环对比 captchaData 和 sliceData,从左到右,每次增加一列,返回校验相同的数量
const equalPoints = [];
// 从左到右,每次增加一列
for (let leftIndex = 0; leftIndex < sliceData[0].length; leftIndex++) {let equalPoint = 0;// 新数组 sliceData 截取 leftIndex - leftIndex + captchaVerifyImage.width 列的数据const compareSliceData = sliceData.map((item) =>item.slice(leftIndex, leftIndex + captchaVerifyImage.width),);// 循环判断 captchaData 和 compareSliceData 相同值的数量for (let h = 0; h < captchaData.length; h++) {for (let w = 0; w < captchaData[h].length; w++) {if (captchaData[h][w] === compareSliceData[h][w]) {equalPoint++;}}}equalPoints.push(equalPoint);
}
// 找到最大的相同数量,大概率为缺口位置
return equalPoints.indexOf(Math.max(...equalPoints));

对比时像素较多,不容易直接看到效果,这里写一个简单的二位数组对比,方便各位理解:

[[0, 1, 0],[1, 0, 1],[0, 1, 0],
]
[[0, 0, 0, 1, 0, 0],[0, 0, 1, 0, 1, 0],[0, 0, 0, 1, 0, 0],
]

循环对比,那么第3列开始,匹配的数量可以达到9,所以返回 3,这样就是滑块要移动的位置。

干扰缺口其实对我们这个识别方式没什么影响,最多可能会增加一些失败的概率,我个人测试了一下,识别成功率有 95% 左右。

总结

这次升级后,掘金的滑块验证码的安全性有了一定的提升,还是可以继续破解的,只是难度有所增加。最后再奉劝大家不要滥用这个技能,这只是为了学习和研究,不要用于非法用途。如果各位蹲局子,可不关我事啊。 🤔️

相关文章:

掘金滑块验证码安全升级,继续破解

去年发过一篇文章&#xff0c;《使用前端技术破解掘金滑块验证码》&#xff0c;我很佩服掘金官方的气度&#xff0c;不但允许我发布这篇文章&#xff0c;还同步发到了官方公众号。最近发现掘金的滑块验证码升级了&#xff0c;也许是我那篇文章起到了一些作用&#xff0c;逼迫官…...

数据结构练习题——Java实现

20240531-时间复杂度 1、消失的数字 方法一&#xff1a;位运算 两个数字一样的数组&#xff0c;其中一个数组中少了一个数字&#xff0c;定义一个变量分别异或两个数组&#xff0c;结果即为缺少的数字 class Solution {public int missingNumber(int[] nums) {int xor 0;int…...

行为设计模式之状态模式

文章目录 概述定义结构图 2.代码示例小结 概述 定义 状态模式(state pattern)的定义: 允许一个对象在其内部状态改变时改变它的行为。 对象看起来似乎修改了它的类。 状态模式就是用于解决系统中复杂对象的状态转换以及不同状态下行为的封装问题.。状态模式将一个对象的状态…...

找回以前的视频:技术与实践3个指南

你们有没有发现现在视频已经成为我们生活中不可或缺的一部分了&#xff1f;不管是在工作场合做演示、在学习时看教学视频&#xff0c;还是在休闲娱乐时追剧看电影&#xff0c;视频都扮演着超级重要的角色。 然而误删或手机故障的发生很可能将以前的视频清除。本文将深入探讨手…...

GCN 代码解析(一) for pytorch

Graph Convolutional Networks 代码详解 前言一、数据集介绍二、文件整体架构三、GCN代码详解3.1 utils 模块3.2 layers 模块3.3 models 模块3.4 模型的训练代码 总结 前言 在前文中&#xff0c;已经对图卷积神经网络&#xff08;Graph Convolutional Neural Networks, GCN&am…...

2024年云计算、信号处理与网络技术国际学术会议(ICCCSPNT 2024)

2024年云计算、信号处理与网络技术国际学术会议&#xff08;ICCCSPNT 2024&#xff09; 2024 International Academic Conference on Cloud Computing, Signal Processing, and Network Technology&#xff08;ICCCSPNT 2024&#xff09; 会议简介&#xff1a; 2024年云计算、…...

希尔排序法

希尔排序为插入排序的优化&#xff0c;即将数组分组&#xff0c;将每一组进行插入排序&#xff0c;每一组排成有序后&#xff0c;最后整体就变有序了。 上面gap2&#xff0c;即5&#xff0c;14&#xff0c;18&#xff0c;27&#xff0c;68为一组&#xff1b;13&#xff0c;20&a…...

thinkphp6.0版本下子查询sql处理

目录 一&#xff1a;背景 二&#xff1a;查询实例 三&#xff1a;总结 一&#xff1a;背景 我们在实际业务的开发过程中&#xff0c;经常会碰到这样的场景&#xff0c;查询某些部门的客户信息&#xff0c;查询下过订单的客户信息。这里查询客户信息实际上就用到了子查询&…...

flowable工作流 完成任务代码 及扩展节点审核人(实现多级部门主管 审核等)详解【JAVA+springboot】

低代码项目 使用flowable 工作流 完成任务代码 详解 可以看到 complete()方法 传递了流程变量参数var 前端传递此参数就可以实现 流程中 审批 更新流程变量参数var 也可以进行更多扩展 实现流程中更新表单内容功能 启动流程实例代码 实现对于流程自定义 动态节点审核人 功…...

【电源专题】一体成型电感为什么需要注意耐压问题

对于电感,我们在电路上使用的很多,如升压、降压、滤波等电路中基本上使用到了电感。电感的种类有很多,电感从不同的角度会有不同的分类。如可以根据否屏蔽、工艺类型、磁性材料类型等可分为多类,这在文章:【分立元件】电感器(inductor)——简介中有做了一些简单的介绍。…...

如何看待时间序列与机器学习?

GPT-4o 时间序列与机器学习的关联在于&#xff0c;时间序列数据是一种重要的结构化数据形式&#xff0c;而机器学习则是一种强大的工具&#xff0c;用于从数据中提取有用的模式和信息。在很多实际应用中&#xff0c;时间序列与机器学习可以结合起来&#xff0c;发挥重要作用。…...

vue图标不显示

静态:有可能路径错误 <img src"../../assets/images/index1.png"> <img src"/assets/images/index2.png"> 动态&#xff1a;需要解析 <div v-for"item in userList" :key"item.id"> <img :src"getUrl(i…...

文件夹如何加密码全攻略,5个文件夹加密方法新手也能学

文件夹如何加密码&#xff1f;在这个互联网时代&#xff0c;隐私保护越来越受到大家的重视。我们在日常工作中&#xff0c;有时候会接触一些比较重要的文件&#xff0c;为了不让这些文件信息被泄露&#xff0c;所以我们可以给文件夹设置密码保护。那要怎么给文件夹设置密码呢&a…...

useState和store的区别

useState 和 useStore 是 React 应用中用于管理数据状态的两种不同的 Hook。它们在功能和用途上有一些区别&#xff1a; useState useState 是 React 提供的一个 Hook&#xff0c;用于在函数组件中添加局部状态。每个 useState 调用都会返回一个数组&#xff0c;包含两个元素…...

vscode远程登录阿里云服务器【使用密钥方式--后期无需再进行密码登录】【外包需要密码】

1&#xff1a;windows主机上生成【私钥】【公钥】 1.1生成公钥时不设置额外密码 1.2生成公钥时设置额外密码【给外包人员使用的方法】 2&#xff1a;在linux服务器中添加【公钥】 3&#xff1a;本地vscode连接linux服务器的配置 操作流程如下 1.1本地终端中【生成免密登录…...

解决uniapp里的onNavigationBarSearchInputClicked不生效

如何在uniapp里使用onNavigationBarSearchInputClicked。 1、在page.json里配置 "pages": [{"path": "pages/index/index","style": {"navigationBarTitleText": "首页","navigationStyle": "cu…...

Windows下搭建Cmake编译环境进行C/C++文件的编译

文章目录 1.下载Cmake2.安装MinGW-w643.进行C/C文件的编译 1.下载Cmake 网址&#xff1a;https://cmake.org/download/ 下载完成后安装&#xff0c;勾选“Add CMake to the system PATH for the current user" 点击Finish完成安装&#xff0c;在cmd窗口验证一下是否安…...

实用新型专利申请材料的撰写与准备

在科技创新日益活跃的今天&#xff0c;实用新型专利的申请与保护显得尤为重要。实用新型专利作为一种重要的知识产权形式&#xff0c;对于推动科技进步、促进经济发展具有重要意义。 首先我们需要明确实用新型专利的定义。实用新型专利是指对产品的形状、构造或者其结合所提出…...

代码随想录算法训练营第60天|● 84.柱状图中最大的矩形

84. 柱状图中最大的矩形 和昨天的思路完全一样 单调栈直接解了 双指针法特别麻烦 class Solution:def largestRectangleArea(self, heights: List[int]) -> int:heights.insert(0,0)heights.append(0)stack[0]res0for i in range(1,len(heights)):while stack and heights…...

让AI给你写代码(9.3):一点改进,支持扩展本地知识库

改进目标&#xff0c;当输入提示问题后&#xff0c;能匹配到本地知识库的需求&#xff0c;然后AI按匹配到的需求给出代码并进行自动测试&#xff1b; 如果无法匹配到本地需求&#xff0c;可以直接输入生成逻辑&#xff0c;再由AI生成&#xff0c;然后支持用户把新需求插入本地库…...

idea大量爆红问题解决

问题描述 在学习和工作中&#xff0c;idea是程序员不可缺少的一个工具&#xff0c;但是突然在有些时候就会出现大量爆红的问题&#xff0c;发现无法跳转&#xff0c;无论是关机重启或者是替换root都无法解决 就是如上所展示的问题&#xff0c;但是程序依然可以启动。 问题解决…...

rknn优化教程(二)

文章目录 1. 前述2. 三方库的封装2.1 xrepo中的库2.2 xrepo之外的库2.2.1 opencv2.2.2 rknnrt2.2.3 spdlog 3. rknn_engine库 1. 前述 OK&#xff0c;开始写第二篇的内容了。这篇博客主要能写一下&#xff1a; 如何给一些三方库按照xmake方式进行封装&#xff0c;供调用如何按…...

聊聊 Pulsar:Producer 源码解析

一、前言 Apache Pulsar 是一个企业级的开源分布式消息传递平台&#xff0c;以其高性能、可扩展性和存储计算分离架构在消息队列和流处理领域独树一帜。在 Pulsar 的核心架构中&#xff0c;Producer&#xff08;生产者&#xff09; 是连接客户端应用与消息队列的第一步。生产者…...

macOS多出来了:Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用

文章目录 问题现象问题原因解决办法 问题现象 macOS启动台&#xff08;Launchpad&#xff09;多出来了&#xff1a;Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用。 问题原因 很明显&#xff0c;都是Google家的办公全家桶。这些应用并不是通过独立安装的…...

高等数学(下)题型笔记(八)空间解析几何与向量代数

目录 0 前言 1 向量的点乘 1.1 基本公式 1.2 例题 2 向量的叉乘 2.1 基础知识 2.2 例题 3 空间平面方程 3.1 基础知识 3.2 例题 4 空间直线方程 4.1 基础知识 4.2 例题 5 旋转曲面及其方程 5.1 基础知识 5.2 例题 6 空间曲面的法线与切平面 6.1 基础知识 6.2…...

镜像里切换为普通用户

如果你登录远程虚拟机默认就是 root 用户&#xff0c;但你不希望用 root 权限运行 ns-3&#xff08;这是对的&#xff0c;ns3 工具会拒绝 root&#xff09;&#xff0c;你可以按以下方法创建一个 非 root 用户账号 并切换到它运行 ns-3。 一次性解决方案&#xff1a;创建非 roo…...

CRMEB 框架中 PHP 上传扩展开发:涵盖本地上传及阿里云 OSS、腾讯云 COS、七牛云

目前已有本地上传、阿里云OSS上传、腾讯云COS上传、七牛云上传扩展 扩展入口文件 文件目录 crmeb\services\upload\Upload.php namespace crmeb\services\upload;use crmeb\basic\BaseManager; use think\facade\Config;/*** Class Upload* package crmeb\services\upload* …...

安全突围:重塑内生安全体系:齐向东在2025年BCS大会的演讲

文章目录 前言第一部分&#xff1a;体系力量是突围之钥第一重困境是体系思想落地不畅。第二重困境是大小体系融合瓶颈。第三重困境是“小体系”运营梗阻。 第二部分&#xff1a;体系矛盾是突围之障一是数据孤岛的障碍。二是投入不足的障碍。三是新旧兼容难的障碍。 第三部分&am…...

MySQL JOIN 表过多的优化思路

当 MySQL 查询涉及大量表 JOIN 时&#xff0c;性能会显著下降。以下是优化思路和简易实现方法&#xff1a; 一、核心优化思路 减少 JOIN 数量 数据冗余&#xff1a;添加必要的冗余字段&#xff08;如订单表直接存储用户名&#xff09;合并表&#xff1a;将频繁关联的小表合并成…...

uniapp 字符包含的相关方法

在uniapp中&#xff0c;如果你想检查一个字符串是否包含另一个子字符串&#xff0c;你可以使用JavaScript中的includes()方法或者indexOf()方法。这两种方法都可以达到目的&#xff0c;但它们在处理方式和返回值上有所不同。 使用includes()方法 includes()方法用于判断一个字…...