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

ASP.NET 驗證碼圖片產生與驗證完整實作 (GDI+ 繪圖)

     編輯:ASP.NET 基礎

前言

驗證碼是防止自動化腳本提交表單的基礎防線。ASP.NET 透過 `System.Drawing` (GDI+) 動態產生包含雜訊線、雜訊點、漸層文字的 GIF 圖片,並將驗證碼存入 Cookie 供後端驗證。本文提供完整前後端整合範例。

架構概覽

  1. 前端頁面:`` + 換圖 JavaScript + 輸入框 + 送出按鈕。
  2. 圖片產生頁:`ValidateImage.aspx` 產生圖片、寫入 Cookie、輸出二進位串流。
  3. 驗證邏輯:送出時比對輸入值與 Cookie 值 (不區分大小寫)。

1. 前端頁面

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Register.aspx.cs" Inherits="Demo.Register" %>
<html>
<head>
    <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
    <script>
        function changeImg() {
            // 加隨機參數防止瀏覽器快取
            $("#imgCheckNo").attr("src", "ValidateImage.aspx?r=" + Math.random());
        }
    </script>
</head>
<body>
    <form id="form1" runat="server">
        <div>
            <img id="imgCheckNo" src="ValidateImage.aspx" style="border:1px solid #000; vertical-align:middle;" />
            <span style="cursor:pointer; color:blue; margin-left:5px;" onclick="changeImg()">看不清?換一張</span>
        </div>
        <div>
            <label>驗證碼:</label>
            <asp:TextBox ID="tbxCheckNo" runat="server" CssClass="tbxCss" />
        </div>
        <div>
            <asp:Button ID="btnSubmit" runat="server" Text="立即註冊" OnClick="btnSubmit_Click" />
        </div>
    </form>
</body>
</html>

2. ValidateImage.aspx - 圖片產生核心

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="ValidateImage.aspx.cs" Inherits="Demo.ValidateImage" %>
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.IO;
using System.Web;

public partial class ValidateImage : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        // 無快取
        Response.Cache.SetCacheability(HttpCacheability.NoCache);
        Response.Cache.SetNoStore();

        string code = GenerateCode(4); // 4 碼
        CreateImage(code);
    }

    private string GenerateCode(int length)
    {
        const string chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
        var rand = new Random();
        char[] code = new char[length];
        for (int i = 0; i < length; i++)
            code[i] = chars[rand.Next(chars.Length)];
        string result = new string(code);

        // 存入 Cookie (HttpOnly 防 XSS)
        var cookie = new HttpCookie("ValidateCode", result) { HttpOnly = true };
        Response.Cookies.Add(cookie);
        return result;
    }

    private void CreateImage(string code)
    {
        int width = (int)Math.Ceiling(code.Length * 18.5);
        int height = 28;
        using (Bitmap bmp = new Bitmap(width, height))
        using (Graphics g = Graphics.FromImage(bmp))
        {
            g.Clear(Color.White);

            // 背景雜訊線
            var rand = new Random();
            for (int i = 0; i < 20; i++)
            {
                g.DrawLine(Pens.LightGray,
                    rand.Next(width), rand.Next(height),
                    rand.Next(width), rand.Next(height));
            }

            // 文字漸層
            using (Font font = new Font("Consolas", 14, FontStyle.Bold | FontStyle.Italic))
            using (var brush = new LinearGradientBrush(
                new Rectangle(0, 0, width, height), Color.Blue, Color.DarkRed, 1.2f, true))
            {
                g.DrawString(code, font, brush, 2, 2);
            }

            // 前景雜訊點
            for (int i = 0; i < 50; i++)
                bmp.SetPixel(rand.Next(width), rand.Next(height), Color.FromArgb(rand.Next()));

            // 邊框
            g.DrawRectangle(Pens.Silver, 0, 0, width - 1, height - 1);

            // 輸出 GIF
            Response.ContentType = "image/gif";
            using (MemoryStream ms = new MemoryStream())
            {
                bmp.Save(ms, ImageFormat.Gif);
                Response.BinaryWrite(ms.ToArray());
            }
        }
    }
}

3. 後端驗證邏輯

protected void btnSubmit_Click(object sender, EventArgs e)
{
    string cookieVal = Request.Cookies["ValidateCode"]?.Value;
    if (string.IsNullOrEmpty(cookieVal) || 
        !string.Equals(cookieVal, tbxCheckNo.Text, StringComparison.OrdinalIgnoreCase))
    {
        ClientScript.RegisterStartupScript(this.GetType(), "err", "alert('驗證碼錯誤!');", true);
        return;
    }

    // 驗證通過,執行註冊邏輯...
    ClientScript.RegisterStartupScript(this.GetType(), "ok", "alert('驗證碼正確!');", true);
}

關鍵安全與體驗優化

項目做法效果
防快取Response.Cache.SetNoStore() + 圖片網址加隨機參數確保每次請求重新產生
Cookie 安全HttpOnly=true、Secure=true (HTTPS)、SameSite=Lax防 XSS、CSRF、跨站洩漏
大小寫不敏感StringComparison.OrdinalIgnoreCase提升使用者友善度
字型選擇Consolas / 等寬字型、斜體、粗體增加機器辨識難度
雜訊干擾背景線、前景點、漸層色、邊框平衡人眼可讀與 OCR 難度
資源釋放using 區塊包裹 Bitmap、Graphics、Font、Brush、Stream防止 GDI+ 物件洩漏導致進程崩潰

現代替代方案建議

  • reCAPTCHA v3 / hCaptcha:零互動行為分析,體驗最佳,免維護圖片產生邏輯。
  • 滑塊/點選驗證:前端互動式,安全性高於傳統圖形驗證碼。
  • 後端限流 + 設備指紋:結合 IP/Device 限制提交頻率,減少驗證碼彈出頻率。

總結

本範例展示 ASP.NET 以 GDI+ 產生驗證碼圖片的完整流程:隨機字元產生 → Cookie 儲存 → 雜訊繪製 → 二進位輸出 → 後端比對。重點在於「資源正確釋放」、「Cookie 安全屬性」、「防快取」三大細節。現代專案建議優先評估第三方驗證服務,降低維護成本並提升安全性。

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