15 分钟用 ML 破解一个验证码系统
人人都恨验证码——那些恼人的图片,显示着你在登陆某网站前得输入的文本。设计验证码的目的是,通过验证你是真实的人来避免电脑自动填充表格。但是随着深度学习和计算机视觉的兴起,现在验证码常常易被攻破。
我拜读了 Adrian Rosebrock 写的《Deep Learning for Computer Vision with Python》。在书中,Adrian 描述了他是怎样用机器学习绕过纽约 E-ZPass 网站上的验证码:
Adrian 无法接触到该应用生成验证码的源代码。为了攻破该系统,他不得不下载数百张示例图片,并手动处理它们来训练他自己的系统。
但是如果我们想攻破的是一个开源验证码系统,我们确实能接触到源代码该怎么办呢?
我访问了 WordPress.org 的插件频道,并搜索了“验证码”。第一条搜索结果是 Really Simple CAPTCHA,并且有超过一百万次的活跃安装:
最好的一点是,它是开源的!既然我们已经有了生成验证码的源代码,那它应该挺容易被攻破的。为了让这件事更有挑战性,让我们给自己规定个时限吧。我们能在 15 分钟内完全攻破这个验证码系统吗?来试试吧!
重要说明:这绝不是对 Really Simple CAPTCHA 插件或对其作者的批评。该插件作者自己说它已经不再安全了,建议使用其他插件。这仅仅是一次好玩又迅速的技术挑战。但是如果你是那剩余的一百多万用户之一,也许你应该改用其他插件 :)
挑战
为了构思一个攻击计划,来看看 Really Simple CAPTCHA 会生成什么样的图片。在示例网站上,我们看到了以下图片:
好了,所以验证码似乎是四个字母。在 PHP 源代码中对其进行验证:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
public function __construct() {
/* Characters available in images */
$this->chars = 'ABCDEFGHJKLMNPQRSTUVWXYZ23456789';
/* Length of a word in an image */
$this->char_length = 4;
/* Array of fonts. Randomly picked up per character */
$this->fonts = array(
dirname( __FILE__ ) . '/gentium/GenBkBasR.ttf',
dirname( __FILE__ ) . '/gentium/GenBkBasI.ttf',
dirname( __FILE__ ) . '/gentium/GenBkBasBI.ttf',
dirname( __FILE__ ) . '/gentium/GenBkBasB.ttf',
);
|
没错,它用四种不同字体的随机组合来生成四个字母的验证码。并且可以看到,它在代码中从未使用 O 或者 I,以此避免用户混淆。总共有 32 个可能的字母和数字需要我们识别。没问题!
计时:2 分钟
工具
在进行下一步前,提一下我们要用来解决问题的工具:
Python 3
Python 是一种有趣的编程语言,它有大量的机器学习和计算机视觉库。
OpenCV
OpenCV 是一种流行的计算机视觉和图片处理框架。我们要使用 OpenCV 来处理验证码图片。由于它有 Python API,所以我们可以直接从 Python 中使用它。
Keras
Keras 是用 Python 编写的深度学习框架。它使得定义、训练和用最少的代码使用深度神经网络容易实现。
TensorFlow
TensorFlow 是 Google 的机器学习库。我们会用 Keras 编程,但是 Keras 并没有真正实现神经网络的逻辑本身,而是在幕后使用 Google 的 TensorFlow 库来挑起重担。
好了,回到我们的挑战吧!
创造我们的数据集
为了训练任何机器学习系统,我们需要训练数据。为了攻破一个验证码系统,我们想要像这样的训练数据:
鉴于我们有 WordPress 插件的源代码,我们可以调整它,一起保存 10,000 张验证码图片及分别对应的答案。
经过几分钟对代码的攻击,并添加了一个简单的 for 循环之后,我有了一个训练数据的文件夹——10,000 个 PNG 文件,文件名为对应的正确答案:
这是唯一一个我不会给你示例代码的部分。我们做这个是为了教育,我不希望你们真去黑 WordPress 网站。但是,我最后会给你生成的这10,000 张图片,这样你就能重复我的结果了。
计时:5 分钟
简化问题
既然有了训练数据,就可以直接用它来训练神经网络了:
有了足够的训练数据,这个方法可能会有用——但是我们可以使问题更简化来解决。问题越简单,要解决它需要的训练数据就越少,需要的计算能力也越低。毕竟我们只有 15 分钟!
幸运的是,验证码图片总是由仅仅四个字母组成。如果我们能想办法把图片分开,使得每个字母都在单独的图片中,这样我们只需要训练神经网络一次识别一个字母:
我没有时间去浏览 10,000 张训练图片并在 Photoshop 中手动把它们拆分开。这得花掉好几天的时间,而我只剩下 10 分钟了。我们还不能把图片分成相等大小的四块,因为该验证码插件把字母随机摆放在不同的水平位置上以防止这一做法:
幸运的是,我们仍然可以自动处理。在图像处理中,常常需要检测有相同颜色的像素块。这些连续像素块周围的界限被称为轮廓。OpenCV 中有一个 LndContours() 函数,可以被用来检测这些连续区域。
所以我们用一个未经处理的验证码图片开始:
接下来把该图片转换成纯黑白(这叫做 thresholding),这样容易找到连续区域:
接着,使用 OpenCV 的 LndContours() 函数来检测该图片中包含相同颜色像素块的不同部分:
接下来就是简单地把每个区域存成不同的图片文件。鉴于我们知道每张图片都应该包含从左到右的四个字母,我们可以利用这一点在保存的同时给字母标记。只要我们是按顺序保存的,我们就应该能保存好每个图片字母及其对应的字母名。
但是等等——我看到一个问题!有时验证码中有像这样重叠的字母:
这意味着我们会把两个字母分离成一个区域:
如果不处理这个问题,会创造出糟糕的训练数据。我们得解决这个问题,这样就不会意外地教机器把两个重叠的字母识别成一个字母了。
一个简单的方法是,如果一个轮廓区域比它的高度更宽,这意味着很可能有两个字母重叠在一起了。在这种情况下,我们可以把重叠的字母从中间拆分成两个,并将其看作两个不同的字母:
既然我们找到拆分出单个字母的方法了,就对所有验证码图片进行该操作。目标是收集每个字母的不同变体。我们可以将每个字母保存在各自对应的文件夹中,以保持条理。
在我分离出所有字母后,我的 W 文件夹长这样:
计时:10 分钟
构建并训练神经系统
由于我们只需要识别单个字母和数字的图片,我们不需要非常复杂的神经网络结构。识别字母要比识别像猫狗这样复杂的图片容易得多。
我们要使用简单的卷积神经网络结构,有两层卷积层以及两层完全连接层:
如果你想要了解更多神经网络的工作,以及为什么它们是图片识别的理想工具,请参考 Adrian 的书或者我之前的文章。
定义该神经网络结构,只需要使用 Keras 的几行代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
# Build the neural network!
model = Sequential()
# First convolutional layer with max pooling
model.add(Conv2D(20, (5, 5), padding="same", input_shape=(20, 20, 1), activation="relu"))
model.add(MaxPooling2D(pool_size=(2, 2), strides=(2, 2)))
# Second convolutional layer with max pooling
model.add(Conv2D(50, (5, 5), padding="same", activation="relu"))
model.add(MaxPooling2D(pool_size=(2, 2), strides=(2, 2)))
# Hidden layer with 500 nodes
model.add(Flatten())
model.add(Dense(500, activation="relu"))
# Output layer with 32 nodes (one for each possible letter/number we predict)
model.add(Dense(32, activation="softmax"))
# Ask Keras to build the TensorFlow model behind the scenes
model.compile(loss="categorical_crossentropy", optimizer="adam", metrics=["accuracy"])
|
现在我们可以训练它了!
1
2
|
# Train the neural network
model.fit(X_train, Y_train, validation_data=(X_test, Y_test), batch_size=32, epochs=10, verbose=1)
|
在 10 通过了训练数据集后,我们达到了几乎 100% 的正确率。此时,我们应该能随时自动绕过这个验证码了!我们成功了!
计时:15 分钟(好险!)
使用训练后的模型来处理验证码
既然有了一个训练后的神经网络,利用它来攻破真实的验证码要很容易了:
- 1.从一个使用 WordPress 插件的网站上下载一张验证码图片。
- 2.使用文章中生成训练数据集的方法,把该验证码图片拆分成四张字母图片。
- 3.用神经网络对每张字母图片分别作预测。
- 4.用四个预测字母作为验证码的答案。
- 5.狂欢!厦门叉车租赁公司
在破解验证码时,我们的模型看起来是这样:
或者从命令来看:
来试试吧!
如果你想自己试试,你可以从这里找到代码( http://t.cn/R8yFJiN )。它包含 10,000 张示例图片和文章中每一步的所有代码。参考文件 README.md 中的运行指导。
但是如果你想了解每一行代码都做了什么,我强烈建议你看看《 Deep Learning for Computer Vision with Python》。该书覆盖了更多的细节,而且有大量的详细示例。这本书是我目前见过的唯一一本既包含了运行原理,又包含了如何在现实生活中用其来解决复杂问题的书。去看看吧!
15 分钟用 ML 破解一个验证码系统的更多相关文章
- 我不是机器人:谷歌最新版验证码系统ReCaptcha破解已开源
选自 Github 作者:George Hughey 机器之心编译 每个人都讨厌验证码,这些恼人的图片中包含你必须输入的字符,我们只有正确地填写才能继续访问网站.验证码旨在确认访问者是人还是程序,并防 ...
- 【干货】零基础30分钟让你拥有一个完整属于自己的短视频APP系统
目录 一.附言: 1 二.购买域名和购买服务器: 2 三.搭建服务器环境: 5 四.配置APP前端部分: 8 1.工具以及文件准备: 9 2.配置后端接口地址 11 3.配置APP启动图和启动图标 ...
- top,它们的意思分别是1分钟、5分钟、15分钟内系统的平均负荷。
理解Linux系统负荷 作者: 阮一峰 日期: 2011年7月31日 一.查看系统负荷 如果你的电脑很慢,你或许想查看一下,它的工作量是否太大了. 在Linux系统中,我们一般使用uptime ...
- 获取当前时间UTC时间的下一个15分钟时间点
ZonedDateTime zdt = ZonedDateTime.now(ZoneOffset.UTC); int now15Minute = zdt.getMinute() / P15MINUTE ...
- [ASP.NET MVC2 系列] ASP.Net MVC教程之《在15分钟内用ASP.Net MVC创建一个电影数据库应用程序》
[ASP.NET MVC2 系列] [ASP.NET MVC2 系列] ASP.Net MVC教程之<在15分钟内用ASP.Net MVC创建一个电影数据库应用程序> ...
- Flask学习之旅--用 Python + Flask 制作一个简单的验证码系统
一.写在前面 现在无论大大小小的网站,基本上都会使用验证码,登录的时候要验证,下载的时候要验证,而使用的验证码也从那些简简单单的字符图形验证码“进化”成了需要进行图文识别的验证码.需要拖动滑块的滑动验 ...
- 使用深度学习来破解 captcha 验证码(转)
使用深度学习来破解 captcha 验证码 本项目会通过 Keras 搭建一个深度卷积神经网络来识别 captcha 验证码,建议使用显卡来运行该项目. 下面的可视化代码都是在 jupyter not ...
- 15分钟带你了解前端工程师必知的javascript设计模式(附详细思维导图和源码)
15分钟带你了解前端工程师必知的javascript设计模式(附详细思维导图和源码) 前言 设计模式是一个程序员进阶高级的必备技巧,也是评判一个工程师工作经验和能力的试金石.设计模式是程序员多年工作经 ...
- 15分钟学会使用Git和远程代码库
git是个了不起但却复杂的源代码管理系统.它能支持复杂的任务,却因此经常被认为太过复杂而不适用于简单的日常工作.让我们诚实一记吧:Git是复杂的,我们不要装作它不是.但我仍然会试图教会你用(我的)基本 ...
随机推荐
- Java Activiti6.0 spring5 SSM 工作流引擎 审批流程 java项目框架
1.模型管理 :web在线流程设计器.预览流程xml.导出xml.部署流程 2.流程管理 :导入导出流程资源文件.查看流程图.根据流程实例反射出流程模型.激活挂起 3.运行中流程:查看流程信息.当前任 ...
- 基于oracle数据库存储过程的创建及调用
1.PLSQL编程 1.1概念和目的 PL/SQL(Procedure Language/SQL) PLSQL是Oracle对sql语言的过程化扩展 指在SQL命令语言中增加了过程处理语句(如分支.循 ...
- Oracle 体系结构五
确定实例是否是RAC数据库的一部分:select parallel from v$instance; 确定数据库是否通过Data Guard备用数据库的保护来防止数据丢失:select protect ...
- iOS项目启动及启动时间优化
app的启动入口Main函数: int main(int argc, char * argv[]) { @autoreleasepool { return UIApplicationMain(argc ...
- 前端基础-jQuery的动画效果
阅读目录 隐藏 显示 切换 下拉 上卷 显示 一.jQuery中隐藏元素的hide方法 让页面上的元素不可见,一般可以通过设置css的display为none属性.但是通过css直接修改是静态的布局, ...
- php文件相关操作
//遍历目录及文件 function myBianli($dirname){ //1.打开 $dir = opendir($dirname); //2.读取 while($filename = rea ...
- Alluxio原理和应用场景随笔
上周末有幸参加了Alluxio(之前也叫Tachyon),七牛云和示说网举办的Alluxio上海Meetup,之前我并没有在真实应用场景中使用过Alluxio,对其适用的应用场景一直报怀疑态度.自信聆 ...
- pci枚举初始化部分(2)
1.2.8判断pcie设备是否支持雷电技术 Intel具有一种基于Thunderbolt技术的PCIE变体,它结合了DisplayPort和PCIe协议,与Mini DisplayPort兼容. Th ...
- 20155310《Java程序设计》实验五(网络编程与安全)实验报告
20155310<Java程序设计>实验五(网络编程与安全)实验报告 一.实验内容及步骤 •任务一: 编写MyBC.java实现中缀表达式转后缀表达式的功能 编写MyDC.java实现从上 ...
- WPF 日历模板改写
原文:WPF 日历模板改写 版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/BYH371256/article/details/83346221 本 ...