验证码工具如何搭建图形验证码

联启 网络工具 3

本文目录导读:

验证码工具如何搭建图形验证码-第1张图片-电脑手机工具软件下载 - 免费实用工具合集 | 联启科技

  1. 核心原理(无论用什么语言)
  2. 具体实现示例(主流语言)
  3. 重要安全加固建议(生产环境必做)
  4. 进阶替代方案
  5. 总结建议

搭建图形验证码有很多方式,主要取决于你的技术栈(后端语言、框架)以及是否需要集成到现有业务中。

目前主流的图形验证码方案可以分为三大类:

  1. 自研方案:自己生成图片或SVG。
  2. 集成开源库:使用成熟的开源验证码工具包(如 captchakaptchadjango-simple-captcha)。
  3. 第三方服务:极验、腾讯防水墙、Cloudflare Turnstile等(这些更多是滑块、点选或行为验证,安全性更高,但非纯图形验证码)。

下面以最常用的 后端生成图片 + 前端展示 方案为例,从原理到具体实现进行说明。


核心原理(无论用什么语言)

  1. 后端生成:在服务器生成一张包含随机字符或图形的图片,同时将正确答案(通常是文本)存入Session或缓存(Redis)。
    • 存入Session:session["captcha_code"] = "A1B2"
    • 存入Redis:SET 用户唯一标识 "A1B2" EX 300(5分钟过期)
  2. 前端展示:后端通过HTTP响应返回图片的二进制流(image/png),前端直接使用 <img src="/captcha"> 展示。
  3. 用户输入:用户在输入框中填写看到的字符。
  4. 后端校验:用户提交表单时,将输入的字符与 session中/redis 中存储的答案进行比对(通常忽略大小写),比对后立即删除该session/缓存,防止重复使用。

具体实现示例(主流语言)

Python(Flask + Pillow 方案)

这是非常经典且上手快的方式,需要安装 Pillow 库用于图像处理。

from flask import Flask, session, make_response, request
from PIL import Image, ImageDraw, ImageFont
import random
import io
app = Flask(__name__)
app.secret_key = 'your-secret-key-here'  # 必须设置,用于签名session
def generate_captcha():
    # 1. 生成随机字符 (4-6位)
    chars = 'ABCDEFGHJKLMNPQRSTUVWXYZ23456789' # 去掉易混淆的 0, O, 1, I
    code = ''.join(random.choices(chars, k=4))
    # 2. 创建图片 (宽度120, 高度40)
    img = Image.new('RGB', (120, 40), color=(255, 255, 255)) # 白色背景
    draw = ImageDraw.Draw(img)
    # 3. 添加干扰线 (3条)
    for i in range(3):
        start = (random.randint(0, 120), random.randint(0, 40))
        end = (random.randint(0, 120), random.randint(0, 40))
        draw.line([start, end], fill=(random.randint(0, 200), random.randint(0, 200), random.randint(0, 200)), width=2)
    # 4. 绘制字符 (注意字体路径,Windows用arial.ttf,Linux需下载)
    font = ImageFont.truetype("arial.ttf", size=30)
    for i, char in enumerate(code):
        x = 10 + i * 25 + random.randint(-3, 3) # 位置随机偏移
        y = random.randint(2, 10)
        draw.text((x, y), char, fill=(random.randint(0, 100), random.randint(0, 100), random.randint(0, 100)), font=font)
    # 5. 添加噪点
    for i in range(50):
        draw.point((random.randint(0, 120), random.randint(0, 40)), fill=(random.randint(0, 255), random.randint(0, 255), random.randint(0, 255)))
    # 6. 保存到内存字节流
    buf = io.BytesIO()
    img.save(buf, format='PNG')
    img_data = buf.getvalue()
    return code, img_data
@app.route('/captcha')
def get_captcha():
    code, img_data = generate_captcha()
    session['captcha_code'] = code # 存入服务器session
    response = make_response(img_data)
    response.headers['Content-Type'] = 'image/png'
    return response
@app.route('/login', methods=['POST'])
def login():
    user_input = request.form.get('captcha_input', '').upper()
    real_code = session.pop('captcha_code', None) # 取出后立刻删除
    if not real_code:
        return '验证码已过期', 400
    if user_input != real_code:
        return '验证码错误', 400
    return '验证成功!'

Java(Spring Boot + EasyCaptcha)

比自研更推荐使用 EasyCaptcha 库,效率高,开箱即用,在 pom.xml 中添加依赖:

<dependency>
    <groupId>com.github.whvcse</groupId>
    <artifactId>easy-captcha</artifactId>
    <version>1.6.2</version>
</dependency>
import com.wf.captcha.SpecCaptcha;
import com.wf.captcha.base.Captcha;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class CaptchaController {
    @GetMapping("/captcha")
    public void captcha(HttpServletResponse response, HttpSession session) throws Exception {
        // 1. 设置响应头
        response.setContentType("image/png");
        response.setHeader("Pragma", "No-cache");
        response.setHeader("Cache-Control", "no-cache");
        response.setDateHeader("Expires", 0);
        // 2. 生成验证码 (宽度160, 高度50, 字符数4)
        SpecCaptcha captcha = new SpecCaptcha(160, 50, 4);
        captcha.setCharType(Captcha.TYPE_ONLY_NUMBER); // 可选:纯数字、纯字母、数字字母混合
        // 3. 存储验证码到Session
        session.setAttribute("captcha_code", captcha.text().toLowerCase()); // 注意大小写
        // 4. 输出图片流
        captcha.out(response.getOutputStream());
    }
}

前端展示与交互(通用HTML/JS)

不论是哪种后端方案,前端代码基本一致:

<form id="loginForm" action="/login" method="post">
    <div>
        <label>用户名:<input type="text" name="username"></label>
    </div>
    <div>
        <label>验证码:<input type="text" name="captcha_input" placeholder="请输入上图字符" required></label>
        <!-- 验证码图片,点击可刷新 -->
        <img id="captcha_img" src="/captcha" alt="验证码" onclick="this.src='/captcha?'+Math.random()" style="cursor:pointer;">
        <span onclick="document.getElementById('captcha_img').src='/captcha?'+Math.random()" style="cursor:pointer; color:blue;">换一张</span>
    </div>
    <button type="submit">提交</button>
</form>

重要安全加固建议(生产环境必做)

  1. 复杂化处理
    • 扭曲变形:对字符进行旋转、波浪形扭曲(Pillow有 transform 方法可做)。
    • 干扰背景:使用随机颜色、渐变、网格线而非纯色。
    • 字体随机:随机从多个字体文件中选取。
  2. 防自动化识别
    • 复杂度:字符粘连在一起(切割难度大增)、加入噪点块。
    • 速度限制:对同一个IP的请求 /captcha 做限速(例如1秒内最多5次)。
    • 一次性使用:验证码校验成功后,必须立即从Session/Redis中删除,绝对不允许复用
  3. 防暴力破解
    • 时效性:验证码有效期通常设为2-5分钟。
    • 尝试次数:用户登录失败3次后,前端必须手动刷新验证码(并重置服务端状态)。
    • 会话绑定:将验证码与Session ID或用户IP绑定,防止A用户的验证码被B用户使用。
  4. 前端安全
    • 计算 /?t=timestamp 加时间戳,或者直接用 Math.random() 加上去,防止图片缓存导致用户一直看到旧code。

进阶替代方案

如果觉得传统图形验证码不安全或用户体验不好,可以考虑:

  1. 行为验证:极验、腾讯防水墙等,用户只需点击“我不是机器人”或拖动滑块,体验更好,安全性显著提升,集成方式主要是前端引用SDK + 后端调用API校验。
  2. Google reCAPTCHA v3:无感验证,根据用户行为给一个风险分数(0.0-1.0),完全无需用户输入字符。
  3. 短信/邮箱验证码:更强的身份验证机制,常用于关键操作(修改密码、大额转账)。

总结建议

  • 如果是学习/小型项目:用Pillow或EasyCaptcha自建即可。
  • 如果是正式商业项目:不要自己造轮子处理图形验证码(识别率低、安全性难保障),推荐集成第三方安全服务(如极验3.0)的前端行为验证 + 后端一次校验。
  • 如果是要求极低但需要图片:使用开源项目调整参数即可。

标签: 搭建工具

抱歉,评论功能暂时关闭!