在現代 Web 應用中,註冊、登入、發布留言等功能若無防護,極易遭遇自動化腳本惡意灌水或暴力破解。隨機驗證碼(CAPTCHA)透過圖形化呈現亂數字元,利用機器難以辨識圖片中扭曲字符與干擾線的特性,有效阻擋非人為操作。
以下採用 HttpServlet 搭配 Java 2D API (BufferedImage, Graphics2D) 實作:
package com.servlet;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.util.Random;
import javax.imageio.ImageIO;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
public class ValidateCodeServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
// 圖片預設尺寸與字元數
private int width = 60;
private int height = 20;
private int codeCount = 4;
private int x = 0;
private int fontHeight;
private int codeY;
// 驗證碼字元池(大寫字母 + 數字)
private char[] codeSequence = {
'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z',
'0','1','2','3','4','5','6','7','8','9'
};
@Override
public void init() throws ServletException {
// 從 web.xml 讀取初始化參數,支援外部配置
String strWidth = getInitParameter("width");
String strHeight = getInitParameter("height");
String strCodeCount = getInitParameter("codeCount");
try {
if (strWidth != null && !strWidth.isEmpty()) width = Integer.parseInt(strWidth);
if (strHeight != null && !strHeight.isEmpty()) height = Integer.parseInt(strHeight);
if (strCodeCount != null && !strCodeCount.isEmpty()) codeCount = Integer.parseInt(strCodeCount);
} catch (NumberFormatException ignored) {}
x = width / (codeCount + 1);
fontHeight = height - 2;
codeY = height - 4;
}
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, java.io.IOException {
// 1. 建立圖片緩衝區
BufferedImage buffImg = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
Graphics2D g = buffImg.createGraphics();
Random random = new Random();
// 2. 填充白色背景
g.setColor(Color.WHITE);
g.fillRect(0, 0, width, height);
// 3. 設定字體與邊框
Font font = new Font("Fixedsys", Font.PLAIN, fontHeight);
g.setFont(font);
g.setColor(Color.BLACK);
g.drawRect(0, 0, width - 1, height - 1);
// 4. 繪製 160 條隨機干擾線
g.setColor(Color.BLACK);
for (int i = 0; i < 160; i++) {
int x1 = random.nextInt(width);
int y1 = random.nextInt(height);
int xl = random.nextInt(12);
int yl = random.nextInt(12);
g.drawLine(x1, y1, x1 + xl, y1 + yl);
}
// 5. 生成隨機驗證碼並繪製
StringBuffer randomCode = new StringBuffer();
for (int i = 0; i < codeCount; i++) {
String strRand = String.valueOf(codeSequence[random.nextInt(36)]);
// 隨機顏色增加辨識難度
int red = random.nextInt(255);
int green = random.nextInt(255);
int blue = random.nextInt(255);
g.setColor(new Color(red, green, blue));
g.drawString(strRand, (i + 1) * x, codeY);
randomCode.append(strRand);
}
// 6. 存入 Session 供後續驗證
HttpSession session = req.getSession();
session.setAttribute("validateCode", randomCode.toString());
// 7. 禁止快取,輸出 JPEG 圖片
resp.setHeader("Pragma", "no-cache");
resp.setHeader("Cache-Control", "no-cache");
resp.setDateHeader("Expires", 0);
resp.setContentType("image/jpeg");
ServletOutputStream sos = resp.getOutputStream();
ImageIO.write(buffImg, "jpeg", sos);
sos.close();
}
}
將 Servlet 註冊並映射 URL,同時透過 <init-param> 客製化圖片尺寸與字元數:
<servlet>
<servlet-name>ValidateCodeServlet</servlet-name>
<servlet-class>com.servlet.ValidateCodeServlet</servlet-class>
<init-param>
<param-name>width</param-name>
<param-value>200</param-value>
</init-param>
<init-param>
<param-name>height</param-name>
<param-value>80</param-value>
</init-param>
<init-param>
<param-name>codeCount</param-name>
<param-value>5</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>ValidateCodeServlet</servlet-name>
<url-pattern>/validateCodeServlet</url-pattern>
</servlet-mapping>
在 JSP 或 HTML 中嵌入圖片並提供「換一張」功能:
<img id="captchaImg" src="/validateCodeServlet" alt="驗證碼" />
<a href="javascript:;" onclick="document.getElementById('captchaImg').src='/validateCodeServlet?t='+Date.now()">看不清,換一張</a>
本文示範了基於 Servlet 的經典驗證碼實作,涵蓋初始化配置、圖形繪製、Session 管理與部署設定。雖然現代專案多採用前後端分離架構,但理解此基礎機制有助於掌握 Web 安全防護的核心邏輯。實務上建議結合成熟的第三方驗證碼服務,兼顧安全性與使用者體驗。