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

構建 ASP.NET MVC4+EF5+EasyUI+Unity2.x 後台管理系統(16):打造專業級驗證碼機制

     編輯:關於ASP.NET

驗證碼是防止暴力破解、機器人惡意註冊與自動化腳本攻擊的第一道防線。本篇分享一個基於 ASHX 一般處理常式實作的專業級驗證碼生成器,支援干擾線、干擾點、隨機字型與色彩,並採用 Session 儲存驗證碼值供後續驗證。

技術架構選擇:為什麼選 ASHX?

  • 輕量級:無頁面生命週期開銷,直接輸出二進位圖片串流
  • 效能優異:繞過完整 ASP.NET 頁面處理管線
  • 快取控制:精確控制 HTTP 標頭防止瀏覽器快取舊驗證碼圖片
  • 跨專案復用:獨立處理常式易於在多個專案間共用

完整實作程式碼:VerifyCode.ashx

using System;
using System.IO;
using System.Drawing;
using System.Drawing.Imaging;
using System.Web;
using System.Web.SessionState;

namespace App.Admin.Core {
    public class VerifyCode : IHttpHandler, IRequiresSessionState {
        
        public void ProcessRequest(HttpContext context) {
            // 圖片尺寸與字型設定
            int codeW = 80, codeH = 22, fontSize = 16;
            string chkCode = string.Empty;
            
            // 色彩池:驗證碼字元、干擾線、干擾點共用
            Color[] colors = { Color.Black, Color.Red, Color.Blue, Color.Green, 
                              Color.Orange, Color.Brown, Color.DarkBlue };
            
            // 字型池:增加識別難度
            string[] fonts = { "Times New Roman", "Verdana", "Arial", "Gungsuh", "Impact" };
            
            // 字元池:排除易混淆字元 (0/O, 1/I/l, 8/B 等)
            char[] chars = { '2','3','4','5','6','8','9',
                            'a','b','d','e','f','h','k','m','n','r','x','y',
                            'A','B','C','D','E','F','G','H','J','K','L','M','N','P','R','S','T','W','X','Y' };
            
            Random rnd = new Random();
            
            // 生成 4 位驗證碼
            for (int i = 0; i < 4; i++) {
                chkCode += chars[rnd.Next(chars.Length)];
            }
            
            // 存入 Session 供驗證使用
            context.Session["VerifyCode"] = chkCode;
            
            // 建立畫布
            using (Bitmap bmp = new Bitmap(codeW, codeH))
            using (Graphics g = Graphics.FromImage(bmp)) {
                g.Clear(Color.White);
                
                // 繪製 1 條干擾線
                for (int i = 0; i < 1; i++) {
                    int x1 = rnd.Next(codeW), y1 = rnd.Next(codeH);
                    int x2 = rnd.Next(codeW), y2 = rnd.Next(codeH);
                    g.DrawLine(new Pen(colors[rnd.Next(colors.Length)]), x1, y1, x2, y2);
                }
                
                // 繪製驗證碼字元(每字元隨機字型、顏色、位置微調)
                for (int i = 0; i < chkCode.Length; i++) {
                    Font ft = new Font(fonts[rnd.Next(fonts.Length)], fontSize);
                    Color clr = colors[rnd.Next(colors.Length)];
                    g.DrawString(chkCode[i].ToString(), ft, new SolidBrush(clr), (float)i * 18 + 2, 0);
                }
                
                // 繪製 100 個干擾點
                for (int i = 0; i < 100; i++) {
                    bmp.SetPixel(rnd.Next(bmp.Width), rnd.Next(bmp.Height), colors[rnd.Next(colors.Length)]);
                }
                
                // 關鍵:禁用快取,確保每次請求都是新驗證碼
                context.Response.Buffer = true;
                context.Response.ExpiresAbsolute = DateTime.Now.AddMilliseconds(0);
                context.Response.Expires = 0;
                context.Response.CacheControl = "no-cache";
                context.Response.AppendHeader("Pragma", "No-Cache");
                
                // 輸出 PNG 圖片串流
                context.Response.ContentType = "image/png";
                using (MemoryStream ms = new MemoryStream()) {
                    bmp.Save(ms, ImageFormat.Png);
                    context.Response.BinaryWrite(ms.ToArray());
                }
            }
        }
        
        public bool IsReusable { get { return false; } }
    }
}

關鍵技術細節解析

技術點實作細節安全效果
字元池過濾移除 0/O, 1/I/l, 8/B, 5/S, 2/Z 等易混淆字元降低使用者辨識錯誤率
隨機字型與色彩每字元獨立隨機選擇字型、大小、顏色破壞 OCR 字元分割與識別
干擾線與干擾點幾何干擾線 + 高密度雜訊點干擾影像二值化與骨架提取
Session 儲存伺服端 Session 儲存,非 Cookie 或隱藏欄位防止客戶端竄改或繞過驗證
完整快取控制Expires=0, Cache-Control=no-cache, Pragma=No-Cache防止瀏覽器快取導致驗證碼不更新
資源釋放using 區塊確保 Bitmap、Graphics、MemoryStream 正確 Dispose防止非受控資源洩漏導致 GDI+ 錯誤

前端整合範例

Razor View 中引用

<img id="imgVerifyCode" src="/Core/VerifyCode.ashx" alt="驗證碼" style="cursor:pointer; vertical-align:middle;" />
<a href="javascript:void(0);" onclick="$('#imgVerifyCode').attr('src', '/Core/VerifyCode.ashx?' + Math.random());">看不清?換一張</a>
<input type="text" id="txtVerifyCode" name="VerifyCode" placeholder="請輸入驗證碼" />

Controller 驗證邏輯

[HttpPost]
public JsonResult Login(LoginViewModel model) {
    string sessionCode = Session["VerifyCode"]?.ToString();
    if (string.IsNullOrEmpty(sessionCode) || 
        !sessionCode.Equals(model.VerifyCode, StringComparison.OrdinalIgnoreCase)) {
        return Json(new { success = false, message = "驗證碼錯誤" });
    }
    // 後續登入驗證邏輯...
}

安全性強化建議

  1. 加入噪聲曲線:使用 Graphics.DrawBezier 繪製貝茲曲線替代直線
  2. 字元扭曲變形:對每字元套用隨機旋轉、縮放、平移矩陣變換
  3. 背景漸層填充:替代純白背景,增加背景複雜度
  4. 限制請求頻率:同一 IP/Session 短時間內請求驗證碼次數限制
  5. 考慮第三方服務:高安全性場景建議整合 Google reCAPTCHA v3 或 hCaptcha

常見問題排查

  • 驗證碼不顯示:檢查專案是否引用 System.Drawing,IIS 應用程式集區身分識別是否具備 GDI+ 權限
  • Session 為 null:確認 IRequiresSessionState 介面已實作,web.config 未停用 Session
  • 中文亂碼:驗證碼僅使用英數字元,不涉及中文編碼問題

此驗證碼機制已在生產環境穩定運行,兼顧安全性與使用者體驗,可直接整合至任何 ASP.NET MVC/Web Forms 專案中。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved