验证码的生成
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
验证码的生成
一.验证码的分类
验证码根据其内容大致可以分为三类:字符验证码(Text.Based CAPTCHA),图像验证码(Image.Based CAPTCHA),以及视频语音等验证码(Other CAPTCHA),其中每一大类又包含若干子类。
1.1 字符验证码
此类验证码是目前网络中的主流验证码,绝大多数网站均采用此类验证码。该验证码首先随机产生的一串字符,然后对字符进行一些处理,最后以图片的形式显示给用户,用户需要正确输入图片上的文字来完成验证。每次页面加载时会产生不同的字符序列,可以抵御简单的自动攻击[1]。简单的验证码示例如下图所示:
没有干扰,字符固定:有干扰噪声点:
字符角度随机旋转并有干扰线:有干扰字符:
字符扭曲变形并有粘连:
其他:
1.2 图像验证码
尽管字符验证码具有诸多优点,然而字符验证码有一个难以避免的缺点:为了安全性增加字符扭曲粘连难度无疑降低了用户体验,部分网站验证码使得用户都难以看清,甚至需要刷新多次才能输入正确,影响用户浏览兴致。因此,即基于图像的验证码悄然兴起,也开始慢慢的普及起来,这种验证码的特点是趣味性高,解答清晰。图像验证码的示例如下图所示:
图1.1 选图验证码
图1.2 滑动验证码
1.3 其他验证码
如。如Gif动画验证码,手机短信验证码,视频验证码,语音验证码等
二.针对字符验证码的生成算法设计
字符验证码的主要设计思路:主要分为前景图层和干扰图层的设计[2]。其中,前景层主要是随机产生字符串,并对字符串进行一些特殊处理,如扩大字符库规模,设置多种字体,对字体进行随机形变处理、随机旋转字符、字符粘连等。而干扰图层主要是生成一些干扰点、干扰线、字符等其他干扰因素,用于干扰和混淆图形验证码中的验证字符串,从而有效地加大图片识别难度,使其成为真正实用的验证码。最后将验证码绘制在有干扰点的背景图片上,用图片形式显示出系统给的随机码。
2.1随机产生字符
在选取候选字符时,首先会考虑数字和英文字符或者两者叠加使用,还可以考虑使用汉字字符,数字字符可取0~9,英文字符可选取26个英文字母,其中,考虑到英文字母有大小写,可增加候选字符数组长度。相比于数字和英文,汉字可选取的范围就大的多得多。2.2字符变形
为了增加程序识别难度,必要的方法是尽量增加特征量库,使验证码能随机地具有不同的特征及特征值。
a)为每一个验证码汉字随机设置不同的字体,且字符字体是随机的,因此一个图形验证码中包含了各种不同的字体,不利于程序破解。
b)为每一个验证码随机的选择形变值,使每一个字符都有不同的形变结果,使简单的破解算法失效。在这个方面,笔者设置的变形效果包括:字符随机向左扭曲、字符随机向右扭曲、进行放大镜效果处理,每一个字符经过这三种变换中的其中一种变换后,最后再进行随机旋转处理。
(a)字符随机向左、向右扭曲为了字符有扭曲效果,使程序难以辨别,但又不对人眼识别造成障碍,使这一个字符像素中的任意一行像素点相对应于上一行有0或1个像素宽度的
向左(向右)偏差,任意一行的向左(向右)偏差值是由代码随机确定的。之所以选择0或1个像素宽度,是因为如果偏移量太多,会造成字符难以辨认;而如果都选择1个宽度,则相当于倾斜了45。,不会有扭曲的效果。经过这样的处理以后,字符有向左(向右)倾斜并有扭曲
的趋势,破坏了汉字规则整齐的田字型结构,如图2.1(a)、(b)所示。
(b)进行放大镜效果处理。除了扭曲效果外,也可以对每个字符的不同部分进行放大或缩小处理,但这种放大或缩小必须是连续而缓慢的,否则容易造成人眼识别困难。
图2.1 形变效果示例图
(c)随机旋转处理。单个字符经过扭曲或放大镜处理后,再对其进行随机旋转处理,使其随机顺时针或逆时针以字符中心点为圆心随机旋转0~150度。
由于现在图像处理技术和ORC技术的成熟,以上这些针对单个字符的形变处理就显得不十分可靠。当N个字符组合为一个图形验证码时,如果能使其互相粘连为一个完整的不易被正确分割的整体时,则程序识别时首先要将其正确的分割为N个部分后才能进行各个字符的识别,若它不能进行正确的分割,则就不可能进行正确的识别。因此,这样做会给程序识别带来非常巨大的困难,而这正是产生文本验证码的重点所在。但是这并不是说对单个字符的形变处理就变得可有可无。正是因为字符不再具有字符原本的归整结构,才使程序分割时难以有特征可寻,降低了分割的正确率和单个字符匹配的正确率。
2.3 宇符粘连
使字符粘连,给程序分割造成障碍。主要分为以下四个步骤:
a)去除字符间的空白背景。为了使每个字符变形时不破坏旁边字符的结构,让各个字符之间都间隔得比较远,因此经过变形后的每个字符之间,都还存在着一定的空白。而变形之后的字符所占的高、宽像素值及起始位置都发生了变化,为了去除字符间的空白背景,先要计算每个字符所占宽度的起始位置。绝大多数的字符经过各种变形后,发现其在横轴上的投影
仍然是连续的,因此决定以设定的字符颜色在横轴上的投影起始坐标作为字符的宽度起始值。然而代码试验后却发现了一个有趣的现象。用Java程序在BMP或JPEG图像格式中显示经过各种变换的中文字符时,并非所有字符像素点的颜色都是设定的颜色c系列的,字符颜色会与背景颜色在颜色上有所交互影响,使这个汉字整体上看上去仍是C颜色的,但实际上它却包含了除c颜色外的一些其他颜色,特别是字符与背景交接的边缘。例如,当设定g.setBackground(color.yellow);g.setcolor(color.blue)时,放大图像后会发现字符边缘出现了除蓝色和黄色之外还有其他颜色,如淡绿色、青色、褐色等。因此笔者以不是背景颜色的像素点在横轴上的投影起始点作为字符的宽度起始值,把Ⅳ个字符的起始值记录下来,然后据此消除字符之间的空白部分,同时缩短整个图形宽度。从记录下来的字符宽度可以看出,经过变形后的字符宽度也呈现随机性,使一些根据字符所占宽度来进行分割字符的算法失效。算法描述如下:
CharacterWidth(b)
(a)设置标志量sign为假;
(b)对于b中的每一列像素:
若sign为假.且这一列包含字符像素,则存储这一列的横轴坐标值作为一个字符的宽度起始值,并且设置sign为真;若sign为真,且这一列不包含字符像素,则存储上一列的
横轴坐标值作为一个字符的宽度结束值,并且设置sign为假;
(c)对于前(N一1)个字符:
若这个字符与下个字符在宽度上存在空白间隔,则移除间隔部分,并根据移除的间隔宽度重新计算后面所有字符的宽度起始值;
(d)返回b。