WEB自动化测试中针对验证码的解决方案 (二)

本文介绍了验证码的主要实现方法,包括“读取式”和“生成式”两种方式,并详细阐述了Xbm图片格式及其动态生成过程,以及其他图片格式验证码图形的动态生成方法。
 说明:本文首发于《程序员》杂志2006年第11期,在此连载,转载请先得到本人同意,谢谢。另,本文与程序员杂志上的内容有少许差异。

验证码的主要实现方法

要解决验证码的问题,我们首先来看看在不同类型的网站上,验证码究竟是如何实现的。

从实现方式上来说,验证码分为“读取式”和“生成式”两种。

读取式”是指从服务器上指定的目录下随机读取预先制作好的图片文件,将图片文件显示在页面上要求用户识别。粗看起来,这种方式的安全性应该比较好,因为网站制作者可以通过精心制作非常难于自动识别的图片,将自动工具自动识别的风险降到最低,但实际上,这种方式存在一个致命的缺点:容易在页面文件中泄漏图片文件的URL,而恶意用户正好可以利用这一点,通过反复尝试访问使用验证码的页面,获得大部分预先制作好的图片文件URL和需要输入的验证码之间的关系,然后通过该对应关系跳过验证码的验证,使验证码失效。

另外,由于该方法需要预先制作大量的图片文件,前期的工作量比较大,因此,目前已经很少有网站完全采用该方式实现验证码技术。

生成式”则是指在程序中通过代码的方式,随机生成一个串,并将该串用图形的方式显示在页面上要求用户识别。这种方式由于实现较为方便,因此目前主要的网站均采用该方法实现验证码。当然,“生成式”也有一定的缺点,例如,由于“生成式”一般利用某种网站开发语言提供的图形函数生成图形,每个字符生成的位图是完全相同的,恶意用户可以利用这一点,使用OCR的方式将位图“翻译”成对应的字符串内容。因此,“生成式”一般还会在生成的图片上叠加背景噪音,增加识别的难度。Hotmail和Gmail等网站更是利用变形、改变颜色等方法让验证码的自动识别变得几乎不可能。

总体来说,“生成式”是依靠程序中的代码在运行时动态生成起到验证作用的图片的,但从其具体实现上来看,这种实现方式依赖于具体的编程语言,以及生成图片的格式。

1.1      Xbm图片格式及其动态生成

x-xbitmap格式的图片(以下简称为Xbm格式)由于其特殊性,是一种广泛被用于验证码的图片格式。该图片格式之所以特殊,在于它并不跟gif,jpg等图片格式一样,是一个二进制图片格式,而是采用ASCII码来表示图形——换句话说,它是一个纯文本文件,必须由操作系统对其进行解释才能显示出相应的图片。

以下是一个xbm文件的内容:

#define counter_width 32

#define counter_height 10

static unsigned char counter_bits[] =  { 0x3c, 0x3c, 0x18, 0x3c, 0x66, 0x66, 0x1c, 0x66, 0xc0, 0xc3, 0x18, 0xc3, 0x60, 0xc3, 0x18, 0xc3, 0x1c, 0xc3, 0x18, 0xc3, 0x60, 0xc3, 0x18, 0xc3, 0xc0, 0xc3, 0x18, 0xc3, 0xc0, 0xc3, 0x18, 0xc3, 0x66, 0x66, 0x18, 0x66, 0x38, 0x7e, , 0x7e };

初看起来,这个文件和图形并没有什么关联,但如果我们新建一个文件,将以上内容复制到文件内并将其保存为test.xbm,然后打开IE窗口,并将该文件直接拖拽到它上面后,我们会惊奇地发现,仿佛变魔术一样,显示出来的并不是这个文件的内容,而是一副图片(见图2)。


熟悉C语言的读者肯定一眼就能看出,上面给出的xbm文件的内容完全就是C代码中的一个数组定义。没错,xbm文件就是采用了一个数组来表示一幅图片的。

在上面的文件内容中,#define counter_width 32 定义的是图片的以象素表示的宽度,一般来说,8个象素的宽度可以用来表示一个字符,因此这里的32可以用来表示本图片显示4个字符。

#define counter_height 10定义了图片的高度,表示该图片中每个字符的高度为10象素。而接下来的数组表示的就是图片显示内容的16进制代码了。

一个16进制的字节可以表示为8位二进制数据,xbm文件用二进制的1表示一个黑色的象素,用二进制的0表示一个白色的象素,因此,一个字节可以表示8个象素。以上面的xbm文件为例,一个32×10象素的图片就需要40个字节来表示。xbm文件是按行描述的,对上面的例子来说,每4个字节表示了一行。

因此,如果我们把上述的数组按照4个字节分组进行排列,就会发现字符和数字之间的对应关系。从图3可以看到,由于一个字节能够表示8个象素,而一个图片上的字符宽度也正好是8个象素,因此,对本例来说,按照4个一组的方式排列,很容易得到数组和图片上显示字符的对应关系。


xbm文件可以表示任意的黑白两色图形,而且非常易于生成,因此不少的asp论坛/聊天室的登陆验证码都是采用这样的方法在asp中动态生成的。不过由于攻击者可以利用这种图形格式的处理过程中的漏洞,制造一个超大的图片而导致系统资源耗尽的情况,在Windows XP的SP2以后,就取消了对该图片格式的默认支持,用户必须通过修改注册表才能获得对该图片格式的支持。

1.2      其他图片格式的验证码图形的动态生成

xbm图片文件格式简单,易于生成,但也存在明显的不足——因为图片只能为黑白两色,因此较为容易被自动工具识别。有鉴于此,目前大部分JSP、PHP和ASP.NET网站都利用这些语言本身提供的图形函数在运行时生成图形。

典型的生成图形的过程包括以下几个步骤:

  1. 生成图形对象;
  2. 用背景色填充图形对象;
  3. 随机生成字符串,随机选择前景颜色,利用程序语言的图形库函数以图形方式向图形对象中写入该字符串;
  4. 向图形对象中增加随机产生的点或者线;
  5. 输出图片文件头,输出图片文件内容。

下面是一段使用PHP编写可以用来产生验证码的代码:

None.gif//生成验证码图片 
None.gif
        Header("Content-type: image/PNG");  
None.gif    
session_start(); 
None.gif    
$auth_num=""
None.gif    
session_register('auth_num'); 
None.gif        
srand((double)microtime()*1000000); 
None.gif        
$auth_num_k = md5(rand(0,9999)); 
None.gif    
$auth_num = substr($auth_num_k,17,5); 
None.gif
None.gif
$im = imagecreate(58,28); 
None.gif        
$black = ImageColorAllocate($im, 0,0,0); 
None.gif        
$white = ImageColorAllocate($im, 255,255,255); 
None.gif        
$gray = ImageColorAllocate($im, 200,200,200); 
None.gif        imagefill(
$im,68,30,$gray); 
None.gif   
None.gif        
//将四位整数验证码绘入图片 
None.gif
        imagestring($im, 5, 10, 8, $auth_num, $black); 
None.gif   
None.gif        
for($i=0;$i<50;$i++)  //加入干扰象素 
None.gif
        { 
None.gif          imagesetpixel(
$im, rand()%70 , rand()%30 , $black); 
None.gif        } 
None.gif   
None.gif        ImagePNG(
$im); 
None.gif        ImageDestroy(
$im); 
None.gif
None.gif

当然,在具体采用该方法生成验证码时,还可以在代码中通过图形变形等手段让图形变得更难以被自动工具识别。

另外,注意在上面的代码中,我们将随机生成的用于生成验证码图片的实际数据保存到了Session中,这一步对于验证码的实现非常关键,网上广泛流传的一篇用PHP实现验证码的文章将验证码对应的实际数据存放在页面的hidden Field中,从安全性的角度来说,这种方式将导致验证码对应的实际数据在客户端可见,只需要通过简单的页面分析即可获得,这就完全失去了验证码抵抗恶意攻击的作用。

1.3      验证码是否正确的验证过程

产生验证码图片只是验证码技术实现的一个步骤,验证码图片在页面上正确显示后,用户需要识别验证码并提交了相应的内容,验证码技术应该能够判断用户的输入与验证码对应的实际数据是否一致。

在具体的实现中,一般是将验证码对应的实际数据存放在服务端的Session中,在验证用户输入的代码中通过比较用户的输入和验证码对应的实际数据是否一致来判断用户输入的验证码是否正确。

仍然以用PHP实现验证码为例,验证用户输入是否正确的代码如下:

None.gifsession_start(); 
None.gif
$num=trim($num); 
None.gif
if($auth_num==$num && $num<>"")
None.gif
None.gif
None.gif   
echo "验证成功"
None.gif}
None.gif
None.gif
else
None.gif
None.gif
None.gif   
echo "验证失败"
None.gif}
None.gif

(未完待续)

转载于:https://www.cnblogs.com/guanhe/archive/2006/12/14/592481.html

<think>好的,我现在需要帮助用户解决在Web自动化测试中提取图形验证码的问题。首先,我得理解用户的需求。用户可能在进行网页自动化测试时遇到了图形验证码的阻碍,需要提取这些验证码以便后续处理,比如识别或者绕过。用户提到了使用Selenium时可能触发验证码的问题,所以需要找到在自动化测试中提取这些图形验证码的方法、工具或技术实现。 首先,我应该回顾已有的知识。图形验证码通常以图片形式嵌入在网页中,可能作为<img>标签,或者通过CSS、JavaScript动态生成。提取的关键在于定位到验证码图片的元素,然后获取其图片数据。常见的工具包括Selenium、Puppeteer等自动化测试工具,可能需要结合截图功能或者直接获取图片的src属性。 接下来,我需要考虑不同的验证码类型。有些验证码是静态的,直接嵌入在HTML中,可以通过获取图片URL下载。而动态生成的验证码可能需要截图整个元素区域。此外,有些网站可能会使用Canvas来渲染验证码,这时候可能需要通过执行JavaScript来获取图像数据。 然后,技术实现方面,可能需要用到Selenium的截图功能,比如element.screenshot()方法,或者使用Pillow库处理图片。对于Canvas,可能需要注入JavaScript代码来提取数据。此外,用户可能需要处理验证码的识别问题,这里可以提到OCR工具如Tesseract,但也要提醒其局限性,比如复杂验证码的识别率低,可能需要第三方服务。 还需要考虑反检测机制。用户提到的引用[1]提到百度可能会检测Selenium,触发验证码。因此,在自动化测试中,可能需要隐藏自动化特征,比如使用undetected-chromedriver或者修改浏览器指纹,但这可能涉及更复杂的技术。 此外,用户提供的引用[2]中有示例验证码图片,可能需要具体分析这些图片的结构,但用户没有提供具体图片,所以需要给出通用方法。 现在,我需要组织这些思路,分步骤回答用户的问题。首先介绍直接提取方法,如定位元素并获取src或截图。然后处理动态生成的情况,比如Canvas。接着讨论OCR识别,最后提到反检测的注意事项。同时,要确保回答符合系统级指令:使用正确的中文,数学公式用$...$,独立公式用$$...$$,生成相关问题,添加引用。 可能需要验证某些技术细节,比如Selenium的截图方法是否适用于所有情况,或者Canvas提取的具体步骤。例如,通过执行脚本获取Canvas的base64数据,然后转换为图像。还要提到第三方库如Pillow处理图像,以及OCR工具的使用。 最后,要生成相关问题,帮助用户深入探索,比如如何处理Canvas验证码,如何提高OCR准确率,或者如何避免被检测为自动化工具。 需要确保回答结构清晰,步骤明确,引用正确,比如在提到反检测时引用[^1],在示例验证码时引用[^2]。</think>在Web自动化测试中提取图形验证码可通过以下技术方案实现,需根据验证码类型选择对应策略: ### 一、直接图像提取方法 1. **静态资源定位** 对于传统<img>标签验证码,使用Selenium定位元素后提取src属性: ```python from selenium import Webdriver driver = Webdriver.Chrome() captcha_element = driver.find_element(By.XPATH, '//img[@class="captcha-img"]') image_url = captcha_element.get_attribute('src') # 直接获取图片URL ``` 2. **元素区域截图** 动态生成的验证码可使用WebDriver内置截图功能: ```python captcha_element.screenshot('captcha.png') # 保存元素区域截图 ``` ### 、Canvas验证码处理 当验证码通过HTML5 Canvas渲染时,需注入JavaScript获取图像数据: ```python canvas_script = """ var canvas = document.querySelector('canvas'); return canvas.toDataURL('image/png').split(',')[1]; """ base64_data = driver.execute_script(canvas_script) with open("captcha.png", "wb") as f: f.write(base64.b64decode(base64_data)) ``` ### 三、图像处理与OCR识别 1. **预处理技术** 使用Pillow库增强识别率: ```python from PIL import Image, ImageFilter img = Image.open('captcha.png').convert('L').filter(ImageFilter.SHARPEN) ``` 2. **OCR工具集成** - Tesseract OCR基础识别: ```python import pytesseract text = pytesseract.image_to_string(img) # 简单文字验证码识别 ``` - 第三方API服务(适合复杂验证码): ```python import requests response = requests.post('https://api.captcha.io', files={'image': open('captcha.png','rb')}) ``` ### 四、反检测注意事项 需配合浏览器指纹修改技术降低触发概率: ```python # 使用undetected_chromedriver规避检测 import undetected_chromedriver as uc driver = uc.Chrome() ``` $$ \text{验证码识别准确率} = \frac{\text{正确识别次数}}{\text{总尝试次数}} \times 100\% $$
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值