首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> JSP 程式設計 >> 關於JSP

JSP驗證碼生成、顯示、驗證與無刷新刷新完整實戰

     編輯:關於JSP

驗證碼是Web表單防暴力破解、防機器註冊的第一道防線。本文提供基於Servlet生成圖片驗證碼、JSP頁面顯示與點擊刷新、服務端Session驗證的完整鏈路代碼(四位字母數字混合、干擾線、抗OCR設計)。

1. Servlet生成驗證碼圖片(ValidateCodeServlet)

package com.example.web;

import javax.servlet.*;
import javax.servlet.http.*;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Random;
import javax.imageio.ImageIO;

public class ValidateCodeServlet extends HttpServlet {
    private static final int WIDTH = 60, HEIGHT = 20, CODE_LENGTH = 4;
    private static final String CHARS = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789"; // 排除易混淆字符

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 關鍵響應頭:禁用緩存,確保每次請求獲取新圖片
        resp.setContentType("image/jpeg");
        resp.setHeader("Pragma", "No-cache");
        resp.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
        resp.setDateHeader("Expires", 0);

        HttpSession session = req.getSession();

        // 1. 創建內存圖片
        BufferedImage image = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
        Graphics g = image.getGraphics();
        Random random = new Random();

        // 2. 繪製背景
        g.setColor(getRandColor(200, 250));
        g.fillRect(0, 0, WIDTH, HEIGHT);

        // 3. 設置字體
        g.setFont(new Font("Times New Roman", Font.PLAIN, 18));

        // 4. 繪製干擾線(155條)
        g.setColor(getRandColor(160, 200));
        for (int i = 0; i < 155; i++) {
            int x = random.nextInt(WIDTH);
            int y = random.nextInt(HEIGHT);
            int xl = random.nextInt(12);
            int yl = random.nextInt(12);
            g.drawLine(x, y, x + xl, y + yl);
        }

        // 5. 生成並繪製驗證碼
        StringBuilder code = new StringBuilder();
        for (int i = 0; i < CODE_LENGTH; i++) {
            char c = CHARS.charAt(random.nextInt(CHARS.length()));
            code.append(c);
            g.setColor(getRandColor(20, 130));
            g.drawString(String.valueOf(c), 13 * i + 6, 16);
        }

        // 6. 存入Session供後續驗證
        session.setAttribute("validateCode", code.toString().toUpperCase());

        // 7. 輸出圖片
        g.dispose();
        ImageIO.write(image, "JPEG", resp.getOutputStream());
    }

    // 顏色工具方法
    private Color getRandColor(int fc, int bc) {
        Random random = new Random();
        if (fc > 255) fc = 255;
        if (bc > 255) bc = 255;
        int r = fc + random.nextInt(bc - fc);
        int g = fc + random.nextInt(bc - fc);
        int b = fc + random.nextInt(bc - fc);
        return new Color(r, g, b);
    }
}

2. web.xml配置

<servlet>
    <servlet-name>ValidateCodeServlet</servlet-name>
    <servlet-class>com.example.web.ValidateCodeServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>ValidateCodeServlet</servlet-name>
    <url-pattern>/validateCode.jpg</url-pattern>  <!-- 偽裝為jpg,利於繞過某些攔截 -->
</servlet-mapping>

3. JSP頁面顯示與點擊刷新

<%@ page contentType="text/html;charset=UTF-8" %>
<html><head>
<script>
    // 點擊圖片/換一張鏈接刷新驗證碼
    function refreshCaptcha() {
        // 關鍵:添加隨機參數防止瀏覽器緩存圖片
        document.getElementById('captchaImg').src = '/validateCode.jpg?' + Math.random();
    }
</script>
</head><body>
<form action="submit.jsp" method="post">
    用戶名:<input name="username"><br>
    驗證碼:<input name="captcha" maxlength="4">
    <img id="captchaImg" src="/validateCode.jpg" alt="點擊刷新" style="cursor:pointer; vertical-align:middle;" onclick="refreshCaptcha()">
    <a href="javascript:refreshCaptcha()">看不清?換一張</a><br>
    <input type="submit" value="提交">
</form>
</body></html>

4. 服務端驗證邏輯(submit.jsp或Controller)

<%
    String inputCode = request.getParameter("captcha");
    String sessionCode = (String) session.getAttribute("validateCode");

    // 驗證:忽略大小寫,驗證後立即移除防重放
    boolean valid = (inputCode != null && sessionCode != null &&
                     inputCode.trim().toUpperCase().equals(sessionCode));
    session.removeAttribute("validateCode"); // 單次使用

    if (!valid) {
        out.println("驗證碼錯誤!<a href='javascript:history.back()'>返回</a>");
        return;
    }
    // 通過,執行業務邏輯...
%>

安全加固清單

現代化演進

  • 前端Canvas繪製驗證碼(canvas.toDataURL()),減少服務端圖片生成壓力。
  • 引入成熟驗證服務:Google reCAPTCHA v3(無感評分)、Geetest極驗、阿里云驗證碼,轉移對抗成本。
  • Spring Boot項目:@Controller + @GetMapping("/captcha") + HttpServletResponse輸出,配合RedisTemplate存儲驗證碼(分布式Session場景)。

「生成→存Session→輸出圖片→前端刷新→後端驗證即銷毀」是經典驗證碼閉環。理解每個環節的安全意義,比複製代碼更重要。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
風險對策
暴力破解(無限嘗試)同IP/同Session限制嘗試次數(如5次鎖定15分鐘),Redis計數器實現
驗證碼重放攻擊驗證成功立即session.removeAttribute(),單次使用
OCR識別破解增加干擾線密度、字符扭曲、噪點、背景幹擾;或升級為行為驗證(滑塊/點選/無感)
CSRF繞過表單攜帶CSRF Token,驗證碼驗證前先校驗Token
圖片緩存導致不刷新URL添加隨機參數?t=timestamp,響應頭Cache-Control: no-store