王培彬 陈少镇 林沛聪 蓝汝琪 熊梓韬 潘志宏
摘要:随着互联网的快速发展,越来越多的网站为了防止用户利用机器人自动注册、登录、灌水,都采用了验证码自动识别技术。然而,简易的验证码依然存在安全风险,为了防止网络爬虫或者恶意攻击的登录操作,本文将通过PaddlePaddle平台进行验证码识别的深度学习,阐述深度学习下网站验证码的破解和防范。实验结果表明:将训练实例的验证码数据训练成预测模型,使用预测模型来自动识别验证码中包含的内容实现验证码自动识别,而将验证码的字符位置随机摆放,可有效防止攻击者对图片进行裁剪分析。
关键词:验证码;自动识别;PaddlePaddle;深度学习;预测模型
中图分类号:TP391 文献标识码:A
文章编号:1009-3044(2019)11-0031-04
Abstract:With the rapid development of the Internet , more and more websites have adopted captcha automatic identification technology in order to prevent users from using robots to automatically register , login and chatter . However , simple captchas still have security risks . In order to prevent the login operation of web crawlers or malicious attacks , this paper will carry out the deep learning of captchas identification of PaddlePaddle platform and explain the cracking and prevention of captchas under deep learning . The experimental results show that the captcha data onto the training example is trained as a prediction model , and the content contained in the captcha is automatically identified by the prediction model , while the random placement of the characters of the captcha can effectively prevent the attacker from cutting and analyzing the image .
Key words:verification code; automatic recognition; paddlepaddle; deep learning; predictive model
当下大部分网站的登录以验证码作为验证登录,以防止网络爬虫或者恶意攻击的登录操作。随着深度学习的不断发展,深度学习在图片识别上的准确率也越来越高。通过利用图像识别技术[1],可以识别一些网站的验证码。我们只有了解的识别的技术原理[2],方可防止网站出现相应的恶意攻击。
PaddlePaddle是百度研发的开源开放的深度学习平台[3],有全面的官方支持的工业级应用模型,涵盖自然语言处理、计算机视觉、推荐引擎等多个领域,并开放多个领先的预训练中文模型。同时支持稠密参数和稀疏参数场景的大规模深度学习[4]并行训练,支持千亿规模参数、数百个几点的高效并行训练,也可提供深度学习并行技术的深度学习框架[5]。PaddlePaddle拥有多端部署能力,支持服务器端、移动端等多种异构硬件设备的高速推理,预测性能有显著优势。目前PaddlePaddle已经实现了API的稳定和向后兼容,具有完善的中英双语使用文档。
1 PaddlePaddle之验证码识别的实现
1.1 数据集介绍与下载
本论文中使用某系统网站作为实验目标,经过观察大量的验证码发现,该网站的验证码只有小写的字母和数字,所以这些类别比较少,所以使得识别更加容易。通过对该验证码进行切割分析[6],可以观察到验证码中的4字符都会出现固定的位置,所以只需要通过固定位置裁剪即可把验证码中的每个字符都裁剪出来。该系统的验证码如下:
通过爬虫程序,可以爬取大量的验证码图片,以下的代码片段就是下载验证码图片的核心代码。
pic = requests.get('http://xxxxxx.aspx?', timeout=500)
pic_name = self.save_path+'/' +str(uuid.uuid1()) + '.png'
with open(pic_name, 'wb') as f:
将每一张验证码命名为其对应的验证码内容,是一个庞大的工作量,特别在训练网络模型的过程中,标注数据是工作量非常巨大的,但也是必需的,数据标注工作量大也是目前深度学习的难点。
1.2 裁剪验证码与生成图像列表
通过标注大量的数据集之后,需要裁剪所有的验证码。通过第一部分已经分析到验证码的分布情况,而数据又已经标注了,根据这些标注信息对图片裁剪,裁剪后的图片只包含一个字符。
经过验证码裁剪,并去掉容易混淆的“9”,“o”,“z”字符,总体可分为33个类别,这也使得模型更容易训练。
由于这些数据集不属于PaddlePaddle自帶数据集,训练需自定义数据集,建立图像列表文件作为数据读取的途径,通过编写一个生成图像列表的程序,把验证码生成一个图像列表。
将已裁剪的数据集生成图片列表,通过下面的代码片段将所有图像和每张图片对应的标签生成图片的相对路径和标签,以便后续训练过程中读取数据。其核心代码片段如下:
for img_path in img_paths:
name_path = path + '/' + img_path # 每张图片的路径
isexist = os.path.exists(data_list_path) # 如果不存在这个文件夹,就创建
if not isexist:
os.makedirs(data_list_path)
if class_sum % 10 == 0: # 每10张图片取一个做测试数据
test_sum += 1
with open(data_list_path + "test.list", 'a') as f:
f.write(name_path + "\t%d" % class_label + "\n")
else:
trainer_sum += 1
with open(data_list_path + "trainer.list", 'a') as f:
f.write(name_path + "\t%d" % class_label + "\n")
class_sum += 1
all_class_images += 1
通过上面的程序,一共会生成trainer.list,test.list,readme.json,其中trainer.list,test.list分布是用来训练和测试的,readme.json包含数据集的信息,通过这个文件可以获取到标签寻对用的字符。
1.3 數据的读取
建立数据列表之后,需要建立数据读取程序,通过这个程序生成的reader,reader是PaddlePaddle读取数据的一种介质。通过使用reader,PaddlePaddle可以在训练的过程中非常便捷地从磁盘读取图片数据,经过预处理再应用于训练。以下的代码片段就是通过上一部分生成的图像列表获取图像路径和标签。
def train_reader(self, train_list, buffered_size=1024):
def reader():
with open(train_list, 'r') as f:
lines = [line.strip() for line in f]
for line in lines:
img_path, lab = line.strip().split('\t')
yield img_path, int(lab)
return paddle.reader.xmap_readers(self.train_mapper, reader,
cpu_count(), buffered_size)
PaddlePaddle的reader是读取图像和对图片进行预处理,通过上述的方式完成读取图片后,需要对图片进行预处理,如下为图片预处理的核心代码片段:
def train_mapper(self, sample):
img, label = sample
# 此处使用本地的image,如果paddlepaddle版本是最新的,也可以使用padd.v2.image
# 因为是灰度图,所以is_color=False
img = paddle.image.load_image(img, is_color=False)
img = paddle.image.simple_transform(img, 38, self.imageSize, True, is_color=False)
return img.flatten().astype('float32'), label
最后结合以上的图片读取和预处理两部分,可以得到一个训练使用的reader。在生成reader之前,通过使用PaddlePaddle的reader按照指定的大小随机裁剪一个方形的图像,这种随机裁剪的预处理操作也是数据增强的一种方式。
1.4 使用PaddlePaddle开始训练
在开始PaddlePaddle的训练之前,需定义一个神经网络作为将要训练的一个模型。本论文使用的神经网络模型是VGG神经网络[7],这个模型是牛津大学VGG(Visual Geometry Group)组在2014年ILSVRC提出的,VGG神经模型的核心是五组卷积操作,每两组之间做Max-Pooling空间降维。同一组内采用多次连续的3X3卷积,卷积核的数目由较浅组的64增多到最深组的512,同一组内的卷积核数目是一样的。卷积之后接两层全连接层,之后是分类层。由于每组内卷积层的不同,有11、13、16、19层这几种模型。根据数据集训练的数量,本论文对VGG做了一定的适配,卷积部分引入了BN层和Dropout操作,BN层全称为Batch Normalization。
conv1 = conv_block(img, 64, 2, [0.3, 0], 3)
conv2 = conv_block(conv1, 128, 2, [0.4, 0])
conv3 = conv_block(conv2, 256, 3, [0.4, 0.4, 0])
conv4 = conv_block(conv3, 512, 3, [0.4, 0.4, 0])
conv5 = conv_block(conv4, 512, 3, [0.4, 0.4, 0])
drop = paddle.layer.dropout(input=conv5, dropout_rate=0.5)
fc1 = paddle.layer.fc(input=drop, size=512, act=paddle.activation.Linear())
bn = paddle.layer.batch_norm(input=fc1,
act=paddle.activation.Relu(),
layer_attr=paddle.attr.Extra(drop_rate=0.5))
fc2 = paddle.layer.fc(input=bn, size=512, act=paddle.activation.Linear())
# 通过神经网络模型再使用Softmax获得分类器(全连接)
out = paddle.layer.fc(input=fc2,
size=10,
act=paddle.activation.Softmax())
在開始PaddlePaddle的训练时,需先导入依赖包,其中有PaddlePaddle的V2包和读取数据的程序。然后创建一个类,再在类中创建一个初始化函数,在初始化函数中来初始化PaddlePaddle。此外,可以通过输入是否是参数文件路径,或者是损失函数,如果为参数文件路径,可使用已训练完成的参数生产参数。如果不传入参数文件路径,可使用传入的损失函数生成参数。之后通过图像的标签信息和分类器生成损失函数,使用损失函数生成初始化参数,再生成优化方法,来创建训练器。最后,在程序中调用相应的函数,就可以开始训练了。其关键代码实现如下:
out = vgg_bn_drop(datadim=datadim)
cost = paddle.layer.classification_cost(input=out, label=lbl)
parameters = self.get_parameters(cost=cost)
momentum_optimizer = paddle.optimizer.Momentum(momentum=0.9)
trainer = paddle.trainer.SGD(cost, parameters, =momentum_optimizer)
trainer.train(reader, 100, event_handler, feeding)
由于训练的过程中把图片设置成灰度图来处理,所以数据集也非常小,训练的速度相对比较快。
在训练过程中,可以借助VisualDL可视化工具查看模型训练的情况,从图1来可以模型收敛得非常好,准确率几乎接近百分之百。
在每一个Pass训练结束之后,都是用测试集对模型进行一次测试,观察模型在测试集的预测情况。从图2来看,模型在测试集的预测有非常好,没有出现过拟合的情况。
1.5 使用PaddlePaddle进行预测
通过之前的训练,得到模型参数,可以使用这些参数进行预测验证码图片。由于传进来的是一个完整的验证码,所以需要对验证码进行裁剪[8]。然后把裁剪后的数据传给PaddlePaddle进行预测。因预测出来的是一个label值,所以还需通过label找到对应的字符。
通过以上操作后,在main入口中调用相对应的程序即可进行验证码的预测流程。其关键代码实现如下:
def load_image(file):
im = Image.open(file)
im = im.resize((32, 32), Image.ANTIALIAS)
im = np.array(im).astype(np.float32)
im = im.transpose((2, 0, 1))
im = im[(2, 1, 0), :, :] # BGR
im = im.flatten()
im = im / 255.0
return im
test_data = []
test_data.append((load_image(image_path),))
probs = paddle.infer(out, parameters, test_data)
lab = np.argsort(-probs) [0][0]
通过PaddlePaddle进行预测,最终得到预测结果输出如下:
第1张预测结果为:0,可信度为:0.966999
第2张预测结果为:9,可信度为:0.664706
第3张预测结果为:1,可信度为:0.780999
第4张预测结果为:3,可信度为:0.959722
预测结果为:0a13
结合大量的数据集训练和预测结果输出,该验证码识别的可信度很高。因此该模型对验证码的识别还是挺准确的。
2 结论
PaddlePaddle是一个易学易用、安全高效的分布式深度学习平台,兼容多种异构硬件,具有优异的训练和预测性能。本实验通过PaddlePaddle对某网站的验证码数据训练一个预测模型,通过使用这个预测模型可以自动识别验证码中包含的内容,而且识别的准确率还挺高。针对这种验证码的字符比较清晰,而且每个字符的位置固定,有利于他人对验证码进行切割分析,训练出一个能够自动识别验证码的神经网络模型。所以在深度学习高速发展的今天,这种验证码很容易被破解,危害网站系统的安全。为了防止这种类型的恶意攻击,网站开发者可以将验证码的字符位置随机摆放,防止攻击者对图片进行裁剪分析,实验也证明对应倾斜角度过大或者重叠部分太多的字符很难识别,网站开发者可以充分利用这一点来防止攻击者利用图像识别技术破解网站验证码,维护网站安全。
参考文献:
[1] 何福泉,李伟烽,林培娜,等.验证码的识别技术分析与研究[J].甘肃科技纵横,2019,48(2):1-4.
[2] 基于卷积神经网络的12306验证码识别[D].华南理工大学, 2017.
[3] AICon 2018开幕百度PaddlePaddle引开发者热议[J].智能机器人,2018(1):19.
[4] 尹宝才,王文通,王立春.深度学习研究综述[J].北京工业大学学报, 2015(1):48-59.
[5] 张铮,王顺帆,董雷.基于深度学习的验证码识别[J].湖北工业大学学报,2018,33(2):5-8+25.
[6] 陈少镇,王培彬,蓝汝琪,曾梓鑫,杨森.移动互联网+师生互动的课程表设计与应用[J].电脑知识与技术,2018,14(04):76-79.
[7] 刘欢,邵蔚元,郭跃飞.卷积神经网络在验证码识别上的应用与研究[J].计算机工程与应用, 2016, 52(18):1-7.
[8] 杨航,蔡浩.中文图片验证码识别方法的研究[J].汕头大学学报(自然科学版),2018,33(3):47-53.
【通联编辑:唐一东】