1 摘要
验证码是目前互联网上非常常见也是非常重要的一个事物,充当着很多系统的 防火墙 功能,但是随时OCR技术的发展,验证码暴露出来的安全问题也越来越严峻。本文介绍了一套字符验证码识别的完整流程,对于验证码安全和OCR识别技术都有一定的借鉴意义。
2 关键词
关键词:安全,字符图片,验证码识别,OCR,Python,SVM,PIL
3 免责声明
本文研究所用素材来自于某旧Web框架的网站 完全对外公开 的公共图片资源。
本文只做了该网站对外公开的公共图片资源进行了爬取, 并未越权 做任何多余操作。
本文在书写相关报告的时候已经 隐去 漏洞网站的身份信息。
本文作者 已经通知 网站相关人员此系统漏洞,并积极向新系统转移。
本报告的主要目的也仅是用于 OCR交流学习 和引起大家对 验证安全的警觉 。
4 引言
关于验证码的非技术部分的介绍,可以参考以前写的一篇科普类的文章:
互联网安全防火墙(1)--网络验证码的科普
里面对验证码的种类,使用场景,作用,主要的识别技术等等进行了讲解,然而并没有涉及到任何技术内容。本章内容则作为它的 技术补充 来给出相应的识别的解决方案,让读者对验证码的功能及安全性问题有更深刻的认识。
5 基本工具
要达到本文的目的,只需要简单的编程知识即可,因为现在的机器学习领域的蓬勃发展,已经有很多封装好的开源解决方案来进行机器学习。普通程序员已经不需要了解复杂的数学原理,即可以实现对这些工具的应用了。
主要开发环境:
python SDK版本
图片处理库
开源的svm机器学习库
关于环境的安装,不是本文的重点,故略去。
6 基本流程
一般情况下,对于字符型验证码的识别流程如下:
7 素材准备
7.1 素材选择
由于本文是以初级的学习研究目的为主,要求 “有代表性,但又不会太难” ,所以就直接在网上找个比较有代表性的简单的字符型验证码(感觉像在找漏洞一样)。
最后在一个比较旧的网站(估计是几十年前的网站框架)找到了这个验证码图片。
原始图:
放大清晰图:
此图片能满足要求,仔细观察其具有如下特点。
有利识别的特点 :
以上就是本文所说的此验证码简单的重要原因,后续代码实现中会用到
不利识别的特点 :
这虽然是不利特点,但是这个干扰门槛太低,只需要简单的方法就可以除去
7.2 素材获取
由于在做训练的时候,需要大量的素材,所以不可能用手工的方式一张张在浏览器中保存,故建议写个自动化下载的程序。
主要步骤如下:
这些都是一些IT基本技能,本文就不再详细展开了。
关于网络请求和文件保存的代码,如下:
def downloads_pic(**kwargs): pic_name = kwargs.get(, None) url = res = requests.get(url, stream=True) with open(pic_path + pic_name+, ) as f: for chunk in res.iter_content(chunk_size=1024): if chunk: # filter out keep-alive new chunks f.write(chunk) f.flush() f.close()
循环执行N次,即可保存N张验证素材了。
下面是收集的几十张素材库保存到本地文件的效果图:
8 图片预处理
虽然目前的机器学习算法已经相当先进了,但是为了减少后面训练时的复杂度,同时增加识别率,很有必要对图片进行预处理,使其对机器识别更友好。
针对以上原始素材的处理步骤如下:
8.1 二值化图片
主要步骤如下:
image = Image.open(img_path) imgry = image.convert() # 转化为灰度图 table = get_bin_table() out = imgry.point(table, )
由PIL转化后变成二值图片:0表示黑色,1表示白色。二值化后带噪点的 6937 的像素点输出后如下图:
1111000111111000111111100001111100000011 1110111011110111011111011110111100110111 1001110011110111101011011010101101110111 1101111111110110101111110101111111101111 1101000111110111001111110011111111101111 1100111011111000001111111001011111011111 1101110001111111101011010110111111011111 1101111011111111101111011110111111011111 1101111011110111001111011110111111011100 1110000111111000011101100001110111011111
如果你是近视眼,然后离屏幕远一点,可以隐约看到 6937 的骨架了。
8.2 去除噪点
在转化为二值图片后,就需要清除噪点。本文选择的素材比较简单,大部分噪点也是最简单的那种 孤立点,所以可以通过检测这些孤立点就能移除大量的噪点。
关于如何去除更复杂的噪点甚至干扰线和色块,有比较成熟的算法: 洪水填充法 Flood Fill ,后面有兴趣的时间可以继续研究一下。
本文为了问题简单化,干脆就用一种简单的自己想的 简单办法 来解决掉这个问题:
下面将详细介绍关于具体的算法原理。
将所有的像素点如下图分成三大类
种类点示意图如下:
其中:
当然,由于基准点在计算区域的方向不同,A类点和B类点还会有细分:
然后这些细分点将成为后续坐标获取的准则。
主要算法的python实现如下: