驗證碼是防止自動化腳本提交表單的基礎防線。ASP.NET 2.0 使用 System.Drawing (GDI+) 動態產生圖片,存入 Session 驗證。本文提供完整中文驗證碼實作:隨機中文字庫、干擾線、雜訊點、Session 儲存、HTTP 輸出圖片流。
<%@ Page Language="C#" %>
<%@ Import Namespace="System.Drawing" %>
<%@ Import Namespace="System.Drawing.Imaging" %>
<%@ Import Namespace="System.Drawing.Text" %>
<script runat="server">
protected void Page_Load(object sender, EventArgs e)
{
// 1. 設定圖片尺寸
int width = 100, height = 30;
using (Bitmap bitmap = new Bitmap(width, height, PixelFormat.Format32bppArgb))
using (Graphics g = Graphics.FromImage(bitmap))
{
// 2. 背景填充
g.Clear(Color.White);
g.FillRectangle(new SolidBrush(Color.White), 0, 0, width, height);
// 3. 字體設定(需伺服器安裝「標楷體」或「微軟正黑體」)
Font font = new Font("標楷體", 16, FontStyle.Bold | FontStyle.Italic);
// Font font = new Font("Microsoft JhengHei", 16, FontStyle.Bold);
// 4. 產生 4 碼隨機中文驗證碼
string[] chars = "我,是,沒,高,天,地,聊,材,盆,濁,小,涯,尖,欠,豬,左,腿,刀,吃,渴,棍,皮,影,歇,草,營,救,稅,說,壞,通,病,二,世,期,春,季,弄,刑,事,警,強,窩,菜,干,什,前,都,哭,拉,面,魚,文,鬼,或,熱,狗,蛋,毛,筆,網,件,構,試,社,幫,耐,燒,粘,蘋,鞋,板,裳,花,海,題,a,e,f,r,9,0,k,2,4,7,1,3,q,w,y,u,v,x,p,s,a,d,8,5,t".Split(',');
Random rnd = new Random();
string code = "";
for (int i = 0; i < 4; i++)
code += chars[rnd.Next(chars.Length)];
Session["ValidateCode"] = code; // 存入 Session
// 5. 繪製干擾背景:隨機矩形填充
g.FillRectangle(new SolidBrush(Color.LightYellow), 0, 0, width, height);
// 6. 繪製干擾線
Pen pen = new Pen(Color.Gray, 1);
for (int i = 0; i < 8; i++)
{
int x1 = rnd.Next(width), y1 = rnd.Next(height);
int x2 = rnd.Next(width), y2 = rnd.Next(height);
g.DrawLine(pen, x1, y1, x2, y2);
}
// 7. 繪製驗證碼文字(逐字元隨機位移、旋轉增加辨識難度)
StringFormat sf = new StringFormat { Alignment = StringAlignment.Center, LineAlignment = StringAlignment.Center };
for (int i = 0; i < code.Length; i++)
{
Brush brush = new SolidBrush(Color.FromArgb(rnd.Next(100, 255), rnd.Next(100, 255), rnd.Next(100, 255)));
float x = 10 + i * 22 + rnd.Next(-2, 3);
float y = 15 + rnd.Next(-2, 3);
g.TranslateTransform(x, y);
g.RotateTransform(rnd.Next(-15, 15));
g.DrawString(code[i].ToString(), font, brush, 0, 0, sf);
g.ResetTransform();
}
// 8. 繪製雜訊點
for (int i = 0; i < 50; i++)
{
int x = rnd.Next(width), y = rnd.Next(height);
bitmap.SetPixel(x, y, Color.FromArgb(rnd.Next(256), rnd.Next(256), rnd.Next(256)));
}
// 9. 輸出圖片流
Response.Clear();
Response.ContentType = "image/jpeg";
bitmap.Save(Response.OutputStream, ImageFormat.Jpeg);
}
}
</script>
<img src="ValidateCode.aspx" id="imgCaptcha" alt="驗證碼" style="cursor:pointer; vertical-align:middle;" onclick="this.src='ValidateCode.aspx?'+Math.random()" />
<input type="text" id="txtCaptcha" name="txtCaptcha" maxlength="4" style="width:60px; ime-mode:disabled;" />
<a href="javascript:void(0);" onclick="document.getElementById('imgCaptcha').click()">看不清?換一張</a>
protected void btnSubmit_Click(object sender, EventArgs e)
{
string userInput = txtCaptcha.Text.Trim();
string sessionCode = Session["ValidateCode"]?.ToString();
if (string.IsNullOrEmpty(sessionCode))
{
lblMsg.Text = "驗證碼已過期,請重新整理";
return;
}
if (string.Equals(userInput, sessionCode, StringComparison.OrdinalIgnoreCase))
{
lblMsg.Text = "驗證通過!";
Session.Remove("ValidateCode"); // 一次性使用
// 執行業務邏輯...
}
else
{
lblMsg.Text = "驗證碼錯誤";
// 可選:記錄失敗次數、鎖定帳號
}
}
| 強化項目 | 實作方式 |
|---|---|
| 字體多樣化 | 隨機選擇「標楷體、微軟正黑體、新細明體、Arial」混合 |
| 文字扭曲變形 | 使用 GraphicsPath.AddString + Matrix 仿射變換 |
| 背景漸層/圖片 | LinearGradientBrush 或載入背景圖片 g.DrawImage |
| 語音驗證碼 | 整合 TTS (System.Speech.Synthesis) 產生 .wav 提供無障礙存取 |
| 分散式 Session | 使用 Redis、SQL Server Session State、ASP.NET Core IDistributedCache |
| 防暴力破解 | IP 限制請求頻率、驗證碼失效時間 (5-10 分鐘)、失敗 N 次鎖定 |
app.UseCaptcha() 社區套件整合上述服務。lock 或改用 SkiaSharp、ImageSharp 跨平台庫。RUN apt-get install -y fonts-wqy-zenhei (Linux) 或複製字體檔。image/jpeg 比 image/gif 壓縮率高、支援漸層色彩。Response.Cache.SetNoStore() 防止瀏覽器快取驗證碼圖片。自製驗證碼適合學習 GDI+ 繪圖與 Session 機制,但生產環境強烈建議採用成熟第三方服務(reCAPTCHA、hCaptcha),安全性、可用性、無障礙、維運成本均更優。若必須自建,請參考上述進階強化項目並定期更新字庫與干擾策略。