目前,不少网站在用户登录、用户提交信息等登录和输入的页面上使用了验证码技术。验证码技术可以有效防止恶意用户对网站的滥用,使得网站可以有效避免用户信息失窃、广告SPAM等问题。但与此同时,验证码技术的使用却使得WEB自动化测试面临了较大的困难。
验证码一般应用在WEB系统涉及登录和输入的页面上,其实现的一般方法是在页面上显示一幅图片,要求用户肉眼识别图片中的信息并将该信息作为输入的一部分进行提交。页面上显示的这幅图片一般是一串随机产生的数字或符号,并且被添加了用于防止识别的背景。验证码的主要目的是为了防止恶意用户利用自动工具(机器人)对用户口令进行暴力破解、恶意注册用户,或是向网站发布令人厌烦的广告信息等。
验证码具有随机性和不易被自动工具识别的特点,当用户访问某个使用验证码的页面时,每次对该相同页面的访问都会得到一个随机产生的不同的验证码,并且,这些验证码具有能够被人工识别,但很难被自动工具识别的特点,这样,自动工具就很难适应使用验证码的页面,从而达到保护网站不被恶意使用的目的。
要解决验证码,需要知道验证码是如何产生的,验证码的生成方式有两种“读取方式”和“生成方式”两种。
读取方式,就是在服务器目录下保存制作好的图片文件,然后显示在Web页面上让用户识别。这种方式完全可以通过url的来破解图片的地址,通过图片地址可以间接的知道图片表示的验证码是什么。所以现在这种方式很少出现了。
生成方式,是通过随机生成字符串,然后利用编程语言的图形库生成验证码图片显示在页面上让用户识别。在生成的时候还可以增加背景的一些噪音,改变字符和背景的颜色,甚至变形字符。这种方式本身如果不是用对字符的变形和在背景增加噪音的情况下,可以通过OCR的技术来识别,但是经过这两种处理后,使得识别变的非常困难。
使用生成式的验证码实现原理:首先服务器端生成随机数,并把它保存在session中,然后利用图形库生成验证图片展现给客户端的用户辨认;用户根据验证码图片输入自己识别的验证码发送给服务器端;服务器端根据session保存的随机数和用户输入的验证码进行对比,如果匹配验证通过,如果不匹配验证失败。
自动化测试解决验证码的问题,最主要的有两种方式,通过识别方法和服务端插入法。这两种方式实现方法上侧重点不同,适用的场合也不同。
识别的方法,完全不用考虑服务端,直接通过图像识别的技术(如OCR技术),通过识别图片来破解验证码。这种方法优点就在于不需要服务器端做任何修改,不用提供任何接口,自动化测试便可以完成自己的验证码识别。但是这种方法也有致命的缺点,就是他的识别成功率的问题,在存在变形和背景加入噪音的验证码中,这种识别率相当的低。如果验证码还存在中文的话,那识别成功率就几乎难以忍受了。这种方法我们在以往的实践经验中,曾经使用OCR技术处理过验证码。但是最近遇到一些验证码,使用OCR的识别率都很低。
简单说明一下为什么OCR的识别率比较低,OCR是光学字符识别的简称,他一般用来识别等大规则字体的图像,比方说他可以扫描印刷的图书,将纸质的书扫描到计算机中形成文本;也可以用来识别证件号码,加快机读证件速度。所以如果在验证不规整或者存在噪点,那么识别率会直线下降。但是市面上有些人做的验证码识别程序为什么识别率那么高而通用的OCR识别程序识别率低呢?由于验证码的生成时的变形和加入噪点是存在规律的,开发者可以通过这些规律,为特定的验证码生成程序编写特定的识别代码,这种情况下的识别率是非常高的。还有为什么中文识别率低?这个就比较好理解了,想想英文只有26个字母,26种形态,我们中文一个字一个形态。还有在OCR识别的时候,他的算法可能会通过识别部分来确认全部,有点盲人摸象的感觉(具体的算法可以参照OCR具体的实现算法),在这种情况下,如果中文有稍微的变形就很难识别的了。如果不能理解这点,想想我们小学学习那些形近字的痛苦,也就知道对于计算机是多难了。
这里补充一下QTP9.5以后加入了ABBYY公司的OCR解决方案,他对验证码的识别率是比较高的。当然silktest2009也加入了OCR识别库,不过我觉得识别率比较低。具体这两个工具OCR的部分,可以参照相关手册。当然开源中也有OCR的项目,目前比较好的叫tesseract-ocr。可以将开源的OCR库加入到自动化测试工程中使用。
服务器插入方法,方法在服务端提供一个可被客户端使用的接口,只要客户端传递过来自己的SessionID,该接口就返回此时正确的Session,这种方法就可以很容易地让自动测试工具直接获取到正确的应该提交的验证码内容。从测试的角度来说,这种方法就等于是在系统上增加了一个测试接口,从而提高了系统的可测试性。这种方法的缺点也很明显,上线的程序一般不会保留这样的缺口,并且如果是做性能测试,通过接口获取验证码,会多一次交互操作,这样测试结果可能会有差异。
session的获取的实现方法,根据使用的语言不同框架不同,可能获取session中验证码的方法有所不一样,但是总的思路是一致的。
这里提供一个java用jsp写的demo,主要是为了说明从session中获取验证码的方法思路是什么样子的:
首先,先来看一下jsp中一般验证码是如何实现的:
<img src="CheckCode.jsp" border="0" alt="验证....... 这个是调用 CheckCode.jsp 文件,生成图片验证码
CheckCode.jsp文件代码如下
String sRand="";
for (int i=0;i<4;i++){
String rand=String.valueOf(random.nextInt(10)); //生成随机数
sRand+=rand;
}
session.setAttribute("rand",sRand); 将随机数据存入session中
简单分析一下,在页面中有一个图片,该图片是通过验证码生成程序来生成的,生成程序首先生成随机数或者随机的字母。然后将随机生成好的代码存入到session中去。
然后,可以通过使用jsp的页面来吧session中的验证码传出来,具体代码如下:
getCheckCode.jsp代码如下
<%
out.print(session.getAttribute("rand"));
%>
最后,在自动化测试脚本中首先CheckCode.jsp来生成图片的验证码,然后打开getCheckCode.jsp来获得验证码,然后讲获得的验证码填入提交的表单中提交。
总结该方法,适合在测试环境中,加入一个获取验证码的页面(或者其他接口),自动化测试通过该页面来获得相应的验证码;当产品上线后,删除获得验证码的页面即可。该方法不适合生产环境,他其实是做了一个后门,从安全角度上讲,是比较危险的。该方法也不适合对验证码加密存储的情况:在实际应用中,可以将随机生成的验证码进行MD5加密存储到session中,用户输入的验证码也需要使用MD5加密后,和session中存在的密文进行对比。大家知道破解md5是非常困难的,如果使用这种方法的话,从session中获得验证码也是不可取的。
在实际使用中也可以通过一些小技巧来解决验证码,这些方法就是通过各种手段来逃避或者获得验证,而这些手段主要是要求开发者在开发的时候留有一定的后门。下面简述几种:
l 使用万能验证码,这种方法就是在判断验证的时候,如果遇到前台输入的是万能验证码,那就不要做验证码校验直接通过。
l 特定用户跳过验证码,这种方法就是如果遇到指定用户登录,那么不管输入什么验证码,验证码校验都通过。
l 使用hidden 控件在页面上显示验证码,就是在使用验证码的页面上,加入一个隐藏的控件,该控件的内容就是验证码。虽然用户看不到但是自动化测试工具可以找到该控件,并获得验证码。当然隐藏控件中的验证码也可以使用加密的方法,自动化测试脚本得到加密的验证后,可以通过解密操作解密验证码。
上述的方法都需要开发对代码进行一定的修改,最好不要在生产环境上做,不然会造成安全漏洞。
作为自动化测试工程师遇到验证码的问题,无疑是非常头疼的。如果在测试环境中,最好能通过接口方法,或者开发后门的方法获取验证码,这样可能更有效。如果上线程序,安全性要求比较高的情况下,只能使用识别的方法。识别的方法可以多尝试几种OCR程序,由于OCR程序的算法不同,可能对于特定的验证码识别的成功率也不同。如果遇到中文的验证码,且那个中文字还变形了,最好的方法就是告诉开发换成英文的,中文的识别率,那真的很低。