购买
下载掌阅APP,畅读海量书库
立即打开
畅读海量书库
扫码下载掌阅APP

3.3 CAPTCHA验证码生成

在很多应用场景中,如果我们遇到无法绕过的CAPTCHA验证码,依然可以通过识别验证码来解决问题。本节将选择几种主流的CAPTCHA验证码讲解验证码,讲解它们的生成与识别原理和过程,主要包括文本验证码、滑块验证码、图片选择验证码和手机验证码等类型。

在讲解验证码识别技术之前,我们先来看看主流验证码的生成原理。基本上,所有类型的传统验证码都遵循图3-4的处理流程。

图3-4 验证码的处理流程

3.3.1 文本验证码的生成

文本验证码是一种比较原始且目前仍在广泛使用的技术。目前,用于生成文本验证码的开源代码库还是比较多的,但基本上都基于相似的生成逻辑,相关生成逻辑大致如下:

步骤01 生成随机字符串。字符串可以包含数字、字母和特殊字符。

步骤02 创建包含验证码文本的图片。根据指定的高度和宽度创建图片,并将文本渲染到图片上。

步骤03 为验证码图片添加背景和噪声。为了提高验证码的破解和识别难度,通常会在图片中添加背景和噪声。

接下来,我们以Google公司开源的验证码生成工具Kaptcha为例来演示如何生成文本验证码。

首先,在项目中添加Kaptcha依赖包。因为我们使用Maven构建工程,所以需要添加Maven依赖包:

     <dependency>
         <groupId>com.github.penggle</groupId>
         <artifactId>kaptcha</artifactId>
         <version>2.3.2</version>
     </dependency>

接下来,需要注意的是,Kaptcha提供了很多可配置属性。通过配置这些属性,我们可以指定验证码的图片大小、支持的字符集以及噪声干扰程度等。表3-1列举了Kaptcha支持的一些配置属性及其作用。

表3-1 Kaptcha主要配置属性

接下来,我们来看具体的代码实现及其效果。

     // 创建Kaptcha实例
     DefaultKaptcha kaptcha = new DefaultKaptcha();
     // 创建Kaptcha配置
     Properties properties = new Properties();
     // 设置验证码字符范围
     properties.setProperty("kaptcha.textproducer.char.string", "0123456789");
     Config config = new Config(properties);
     kaptcha.setConfig(config);
     // 生成验证码文本
     String text = kaptcha.createText();
     // 创建验证码图片
     BufferedImage image = kaptcha.createImage(text);
     // 保存验证码图片
     ImageIO.write(image, "png", new File(“captcha.png"));

上述代码成功运行之后,我们就会得到一幅验证码图片,具体效果如图3-5所示。

图3-5 文本验证码生成样例

3.3.2 滑块验证码的生成

近几年,以滑块验证码为代表的行为式验证码被越来越多的平台采用,不仅提高了机器破解的难度,还提升了用户体验。滑块验证码的工作原理和流程如下:

步骤01 生成验证码图片。

(1)从服务器随机选择一幅背景图片和滑块模板图片,随机生成滑块所在的 x y 坐标。

(2)使用选定的背景图片和滑块模板图片生成两幅新的图片。

● 滑块图片:只包含被抠出的区域图像的图片。

● 新的背景图片:包含标记抠图区域的背景图片。

步骤02 保存校验信息并发送滑块验证码给客户端。

(1)将滑块在背景图片的坐标信息与session_id进行绑定并存储。

(2)将包含两幅图片和session_id的数据返回给客户端。

步骤03 记录用户对滑块验证码的操作行为。

(1)用户在客户端进行滑块验证时,记录用户的操作轨迹和最终滑动位置坐标。

(2)客户端将滑动位置坐标、操作轨迹等行为数据和session_id发送到服务器端进行验证。

步骤04 服务器端验证用户提交的行为数据。

(1)服务器端根据接收到的session_id从存储中检索出相应的滑块验证码校验信息,然后将用户提交的行为数据与预先存储的校验信息进行对比,并根据预定义的阈值判断验证是否通过。

(2)(可选操作)服务器端在检查用户提交的行为数据时可能会添加反作弊检查,例如滑块拖动轨迹是否合理、滑块移动速度是否合理等。

在开始编写实现代码之前,我们还需要了解有关图片RGBA颜色模型的基础知识。相较于RGB颜色模型,RGBA颜色模型多了Alpha通道,Alpha通道表示像素的透明度,其取值范围通常为0(完全透明)~255(完全不透明)。无论是在滑块验证码的生成还是识别过程中,都会使用到RGBA中的Alpha通道。

现在,正式开始编写滑块验证码生成的示例代码。本次实验的示例代码只会生成滑块验证码的背景图片和滑块图片,不会涉及滑块验证码的验证逻辑。

     // 1. 从服务器随机选择一幅背景图片和一幅滑块模板图片,并且生成抠图区域的x、y坐标
     BufferedImage originalImage = ImageIO.read(selectedImage);
     BufferedImage sliderTemplateImage = ImageIO.read(selectedSlider);
     Random random = new Random();
     // 随机生成的x坐标
     int x = random.nextInt(originalImage.getWidth() - sliderTemplateImage.getWidth());
     int y = random.nextInt(originalImage.getHeight() - sliderTemplateImage.getHeight());
     // 随机生成的y坐标
     // 2. 使用选定的图片和抠图区域,生成两幅图像
     // 2.1 滑块图片
     BufferedImage sliderImage = new BufferedImage(sliderTemplateImage.getWidth(),
sliderTemplateImage.getHeight(), BufferedImage.TYPE_INT_ARGB);
     for(int i = 0; i < sliderTemplateImage.getWidth(); i++) {
         for(int j = 0; j < sliderTemplateImage.getHeight(); j++) {
             int rgb = sliderTemplateImage.getRGB(i, j);
             // 如果滑块模板图片的像素点Alpha通道值大于100,就使用原始图片的像素点,否则使用滑块模板
             // 图片的像素点
             if((rgb & 0xFF000000) >>> 24 > 100) {
                 sliderImage.setRGB(i, j, originalImage.getRGB(x + i, y + j));
             } else {
                 sliderImage.setRGB(i, j, rgb);
             }
         }
     }
     // 2.2 去掉滑块图片的背景图片
     Graphics2D g2d = originalImage.createGraphics();
     g2d.drawImage(sliderTemplateImage, x, y, sliderTemplateImage.getWidth(),
sliderTemplateImage.getHeight(),null);
     g2d.dispose();
     // 3. 保存两幅图像
     ImageIO.write(originalImage, "png", new File("shadow.png"));
     ImageIO.write(sliderImage, "png", new File("cutout.png"));

上述代码成功执行后,就会生成滑块验证码的两幅图片,分别是背景图片和滑块图片,效果如图3-6和图3-7所示。

图3-6 滑块验证码背景图片

图3-7 滑块验证码滑块图片

3.3.3 点选验证码的生成

点选验证码(Click-based CAPTCHA)是一种常见的验证码形式,其目的是通过用户的点击行为来验证其身份。对于自动化程序来讲,点选验证码的识别复杂性要高于文本验证码和滑块验证码。因为相对于文本验证码和滑块验证码,自动化程序通常更难理解人类在点选验证码上的点击行为。点选验证码一般分为文字点选验证码和图标点选验证码。相关验证码的展示效果如图3-8所示。

图3-8 点选验证码示例图

接下来介绍文字点选验证码的生成流程和实现思路。文本点选验证码的具体工作流程如下:

(1)从图库中随机选择一幅图片作为点选验证码的背景图片。

(2)从字库或词库中随机选择指定数量的文字。

(3)为每个文字随机生成在背景图片上的坐标位置。

(4)随机选择字体颜色和样式。

(5)在背景图片上绘制文字。

(6)记录文字的顺序和坐标位置并与session_id进行绑定,用于后续验证用户点击行为的正确性。

(7)将写入文字的背景图片发送给客户端。

(8)用户按照要求点击图片中的文字。

(9)客户端将用户的点击行为数据发送给服务器端。

(10)服务器端验证用户点击行为的正确性。

根据上述流程,用于生成文字点选验证码实现代码如下(仅包含文字点选验证码的图片部分,不包含其他处理逻辑):

     int NUM_TEXTS = 4;
     File backgroundFile = new File("$IMAGE_PATH/backgound_image.jpeg");
     BufferedImage backgroundImage = ImageIO.read(backgroundFile);
     String[] texts = {"爬","虫","系","统"};
     Graphics2D graphics = backgroundImage.createGraphics();
     int areaWidth = backgroundImage.getWidth() / 4;
     for (int i = 0; i < NUM_TEXTS; i++) {
         String text = texts[i];
         int x = areaWidth * i + random.nextInt(areaWidth);
         int y = random.nextInt(backgroundImage.getHeight() - 20) + 10;
         Color color = new Color(random.nextInt(256), random.nextInt(256),
random.nextInt(256));
         Font font = new Font("Arial", Font.BOLD, 36 + random.nextInt(10));
         graphics.setColor(color);
         graphics.setFont(font);
         graphics.drawString(text, x, y);
     }
     ImageIO.write(backgroundImage, "jpeg", new File("click_captcha.jpeg"));

上述代码成功执行之后,我们会看到对应的点选验证码图片,如图3-9所示。

图3-9 点选验证码背景图片 uRMwG4Bkw2U+mXKsOoPF56hQZdvofQV/9HmHRRzBd6/mrpkKF8ZjoOrm2wgUJ8RC

点击中间区域
呼出菜单
上一章
目录
下一章
×