The Will Will Web

記載著 Will 在網路世界的學習心得與技術分享

如何用 ASP.NET 實做簡單的圖片驗證機制(Captcha)

我之前推薦過一套 reCAPTCHA 線上服務非常的好用,不止可以有效阻擋程式機器人對網頁進行灌水,還可以對英文不好圖像解析能力不夠好的人進行阻擋,說真的,有時後他們會模糊到有些字我也無法解讀,之前我們就有客戶抱怨說 reCAPTCHA 提供的驗證圖實在太不清楚了,希望我們提供一個簡易的版本,否則他們網站的使用者可能會不願意使用他們的網站,因此我就寫了一個簡易版的 Captcha 程式。

一般來說 Captcha 機制都是透過 Session 進行驗證,所以 Captcha 圖片都是透過程式送出,而在圖片送出前將顯示在圖片上的文字寫入到 Session["Captcha"] 中,等原本的網頁表單送出時進行 Session["Captcha"] 與使用者於網頁上輸入的文字進行比對,即可完成 Captcha 的驗證程序。

以下是我之前寫的「超簡易 Captcha 程式」,任何一套入門級的 OCR 軟體應該都能輕易辨識,所以建議僅用於流量小或人氣不是很旺的小網站中,否則建議對圖像多做出一些變化以避免較強的程式機器人攻擊。

只要新增一個 BuildCaptcha.aspx 頁面 ( 你要自己改成 HttpHandler 或 Generic Handler 也行 ),程式碼如下,我附有非常詳細的註解供參:

<%@ Page Language="C#" EnableSessionState="True" %>
<%@ Import Namespace="System.Drawing" %>
<%@ Import Namespace="System.Drawing.Text" %>
<%@ Import Namespace="System.Drawing.Imaging" %>
<script runat="server">
    protected void Page_Init(object sender, EventArgs e)
    {
		// (封裝 GDI+ 點陣圖) 新增一個 Bitmap 物件,並指定寬、高
        Bitmap _bmp = new Bitmap(60, 20);
		
		// (封裝 GDI+ 繪圖介面) 所有繪圖作業都需透過 Graphics 物件進行操作
        Graphics _graphics = Graphics.FromImage(_bmp);
        _graphics.Clear(Color.Black);
		// 如果想啟用「反鋸齒」功能,可以將以下這行取消註解
        //_graphics.TextRenderingHint = TextRenderingHint.AntiAlias;

        // 設定要出現在圖片上的文字字型、大小與樣式
        Font _font = new Font("Courier New", 12, FontStyle.Bold);

		// 產生一個 5 個字元的亂碼字串,並直接寫入 Session 裡
		// 請參考: http://www.obviex.com/Samples/Password.aspx )
        Session["Captcha"] = RandomPassword.Generate(5, 5);

        // 將亂碼字串「繪製」到之前產生的 Graphics 「繪圖板」上
        _graphics.DrawString(Convert.ToString(Session["Captcha"]), 
            _font, Brushes.White, 3, 3);

        // 輸出之前 Captcha 圖示
        Response.ContentType = "image/gif";
        _bmp.Save(Response.OutputStream, ImageFormat.Gif);
		
		// 釋放所有在 GDI+ 所佔用的記憶體空間 ( 非常重要!! )
        _font.Dispose();
        _graphics.Dispose();
        _bmp.Dispose();

		// 由於我們要輸出的是「圖片」而非「網頁」,所以必須在此中斷網頁執行
        Response.End();
    }
</script>

然後將此 Captcha 圖片連結套用到你的頁面上即可,以下範例包括「重新產生 Captcha 圖片」的程式。

<img id="captcha" src="BuildCaptcha.aspx" />
<input type="button" value="變更圖片"
       onclick="captcha.src='BuildCaptcha.aspx?r=' + (new Date()).getTime()" />

特別需要一提的是「圖片上的文字」若需要同時顯示「數字」與「英文」者,必須要考量到有些字很容易被誤判,例如:I、l、1 這三個字就很不容易區分,還有 O、o、0 在特定字型下也是一樣,另外也建議「特殊符號」不要出現在 Captcha 的文字中。

我在程式碼中有提到 How To: Generate a Random Password (C#/VB.NET) 所提供的範例程式蠻不錯的,但他的密碼產生器有包括特殊符號,建議下載回來後可以修改他的程式將特殊符號的部分移除。

相關連結