ASP.NETでのCAPTCHA画像生成手法

ウェブサイトでよく使用されるCAPTCHA画像の生成方法について解説します。主な実装手順は以下の通りです:

  1. HttpHandlerを使用してランダムなCAPTCHA画像を生成
  2. JavaScriptで非同期に画像を更新

実装例

以下のコードはASP.NETでCAPTCHA画像を生成するHttpHandlerの実装例です:

public class CaptchaGenerator : IHttpHandler
{
    private static readonly Random random = new Random();
    private static readonly Brush[] availableBrushes = GetAvailableBrushes();
    private static readonly Pen[] availablePens = GetAvailablePens();
    
    private const int CharWidth = 45;
    private const int ImageHeight = 60;

    public void ProcessRequest(HttpContext context)
    {
        int charCount = 6;
        if (!string.IsNullOrEmpty(context.Request.QueryString["count"]))
        {
            int.TryParse(context.Request.QueryString["count"], out charCount);
        }

        using (Bitmap image = new Bitmap(CharWidth * charCount, ImageHeight))
        using (Graphics graphics = Graphics.FromImage(image))
        {
            graphics.Clear(Color.White);
            
            string captchaText = GenerateRandomText(charCount);
            DrawText(graphics, captchaText);
            DrawNoise(graphics, image.Width, image.Height);
            
            context.Response.ContentType = "image/jpeg";
            image.Save(context.Response.OutputStream, ImageFormat.Jpeg);
        }
    }

    private string GenerateRandomText(int length)
    {
        const string chars = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789";
        return new string(Enumerable.Repeat(chars, length)
            .Select(s => s[random.Next(s.Length)]).ToArray());
    }

    private void DrawText(Graphics graphics, string text)
    {
        for (int i = 0; i < text.Length; i++)
        {
            Brush brush = availableBrushes[random.Next(availableBrushes.Length)];
            graphics.DrawString(
                text[i].ToString(), 
                new Font("Arial", CharWidth - 10, FontStyle.Bold), 
                brush, 
                new PointF(i * CharWidth + 5, 5));
        }
    }

    private void DrawNoise(Graphics graphics, int width, int height)
    {
        int noiseCount = random.Next(15, 25);
        for (int i = 0; i < noiseCount; i++)
        {
            Pen pen = availablePens[random.Next(availablePens.Length)];
            PointF start = new PointF(random.Next(width), random.Next(height));
            PointF end = new PointF(random.Next(width), random.Next(height));
            graphics.DrawLine(pen, start, end);
        }
    }

    private static Brush[] GetAvailableBrushes()
    {
        return typeof(Brushes).GetProperties(BindingFlags.Public | BindingFlags.Static)
            .Where(p => p.PropertyType == typeof(Brush) && p.Name != "White")
            .Select(p => (Brush)p.GetValue(null))
            .ToArray();
    }

    private static Pen[] GetAvailablePens()
    {
        return typeof(Pens).GetProperties(BindingFlags.Public | BindingFlags.Static)
            .Where(p => p.PropertyType == typeof(Pen))
            .Select(p => (Pen)p.GetValue(null))
            .ToArray();
    }

    public bool IsReusable => false;
}

HTMLでの使用方法

生成したCAPTCHAをページに表示する方法:

<div id="captcha-container">
    <img id="captcha-image" src="/CaptchaGenerator.ashx?count=6" alt="CAPTCHA" />
    <button onclick="refreshCaptcha()">画像を更新</button>
</div>

<script>
function refreshCaptcha() {
    var img = document.getElementById('captcha-image');
    img.src = '/CaptchaGenerator.ashx?count=6&t=' + new Date().getTime();
}
</script>

この実装では、以下の点に注意してください:

  • セキュリティ向上のため、単純な数字ではなく英数字混合を使用
  • 画像更新時にキャッシュを回避するため、タイムスタンプパラメータを追加
  • 視認性を考慮し、背景色を白に設定

タグ: ASP.NET CAPTCHA HttpHandler 画像生成 C#

8月9日 00:20 投稿