Web 系統面臨嚴峻安全挑戰,常見攻擊為「枚舉字典暴力破解」:駭客取得帳號後,編寫程式模擬瀏覽器透過 HTTP 協定高速嘗試密碼組合(如 6 位數字僅 100 萬種),若無防禦機制,單機每秒測試 10 次,約 27 小時即可破解。傳統用戶端防禦(ActiveX、USB 金鑰、客戶端程式)終究在駭客控制的環境中可被逆向分析繞過,根本不可靠。
驗證碼利用「電腦擅長邏輯運算、不擅長圖像識別;人腦擅長圖像識別、不擅長高頻重複勞動」的差異:
駭客程式無法自動識別圖片,只能人工逐張辨識輸入,將原本自動化的百萬次嘗試轉為人工操作,成本極高,有效癱瘓枚舉攻擊。合成語音、表情辨識等同理可作為替代媒介。
checkimage.aspx專責生成驗證碼圖片,無 HTML 輸出,Page_Load 執行核心邏輯:
// 1. 產生隨機驗證碼文字 (4-6 碼英數)
Random rand = new Random();
int len = rand.Next(4, 6);
char[] chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ".ToCharArray();
StringBuilder myStr = new StringBuilder();
for (int i=0; i<len; i++) myStr.Append(chars[rand.Next(chars.Length)]);
string text = myStr.ToString();
Session["checkcode"] = text; // 儲存供驗證
// 2. 計算圖片尺寸
Size ImageSize = Size.Empty;
Font myFont = new Font("MS Sans Serif", 20);
using (Bitmap bmp = new Bitmap(10,10))
using (Graphics g = Graphics.FromImage(bmp)) {
SizeF size = g.MeasureString(text, myFont, 10000);
ImageSize.Width = (int)size.Width + 8;
ImageSize.Height = (int)size.Height + 8;
}
// 3. 繪製驗證碼文字
using (Bitmap bmp = new Bitmap(ImageSize.Width, ImageSize.Height))
using (Graphics g = Graphics.FromImage(bmp)) {
g.Clear(Color.White);
using (StringFormat f = new StringFormat()) {
f.Alignment = StringAlignment.Near;
f.LineAlignment = StringAlignment.Center;
f.FormatFlags = StringFormatFlags.NoWrap;
g.DrawString(text, myFont, Brushes.Black,
new RectangleF(0,0,ImageSize.Width,ImageSize.Height), f);
}
// 4. 製造噪點 (佔 30% 面積)
int num = ImageSize.Width * ImageSize.Height * 30 / 100;
for (int i=0; i<num; i++) {
int x = rand.Next(ImageSize.Width);
int y = rand.Next(ImageSize.Height);
Color c = Color.FromArgb(rand.Next(255), rand.Next(255), rand.Next(255));
bmp.SetPixel(x, y, c);
}
// 5. 輸出 PNG 串流
MemoryStream ms = new MemoryStream();
bmp.Save(ms, ImageFormat.Png);
Response.ContentType = "image/png";
ms.WriteTo(Response.OutputStream);
ms.Close();
}
myFont.Dispose();
public static bool CheckCode(string text) {
string txt = HttpContext.Current.Session["checkcode"] as string;
return text == txt;
}
login.aspx
介面含帳號、密碼、驗證碼三輸入框,驗證碼輸入框旁放置 <img src="checkimage.aspx"> 顯示圖片。登入按鈕邏輯:
private void cmdOK_Click(object sender, EventArgs e) {
string UserName = txtUserName.Text;
string Password = txtPassword.Text;
string CheckCode = txtCheckCode.Text;
if (UserName == "張三" && Password == "abc" && checkimage.CheckCode(CheckCode)) {
lblResult.Text = "<b>登入成功</b>";
RegisterStartupScript("a", "<script>alert('登入成功');</script>");
} else {
lblResult.Text = "<font color=red><b>登入資訊錯誤,請重新輸入</b></font>";
}
}
若圖片難以辨識,用戶可雙擊圖片重新載入:
<img src="checkimage.aspx"
title="看不清楚,雙擊圖片換一張。"
ondblclick="this.src = 'checkimage.aspx?flag=' + Math.random()"
border="1">
ondblclick 附加隨機 flag 參數強制瀏覽器繞過快取重新請求,伺服器重新生成驗證碼文字與圖片,Session 同步更新,安全性與易用性並重。
驗證碼大幅提升安全性,但增加用戶操作步驟、降低可用性(特別是視障用戶)。實務應根據系統風險等級、用戶群體特性決定是否啟用、採用何種強度(字元長度、干擾程度)、是否提供語音替代方案等。
本講透過驗證碼案例,展示圖形程式設計在 Web 安全領域的關鍵應用。核心技術包含:System.Drawing 動態生成圖片、Graphics.MeasureString 計算尺寸、DrawString 繪製文字、SetPixel 製造噪點、MemoryStream 串流輸出、Session 跨請求狀態保持。圖形程式設計應用廣泛,為多種技術提供底層支撐。