引言:验证码在Web安全中的重要性

验证码(CAPTCHA)是”Completely Automated Public Turing test to tell Computers and Humans Apart”的缩写,即全自动区分计算机和人类的公开图灵测试。在Web应用中,验证码是防止恶意机器人攻击、垃圾注册、暴力破解等安全威胁的重要防线。

虽然现代Web开发更多使用PHP、Python、Node.js等后端技术,但在某些特定场景下(如遗留系统维护、企业内部应用、ASP经典环境等),VBScript仍然发挥着重要作用。本文将详细介绍如何使用VBScript生成网页验证码,包括基础原理、代码实现、优化技巧和实战案例。

1. VBScript验证码生成基础原理

1.1 验证码生成流程

验证码生成的核心流程包括:

  1. 随机字符串生成:创建随机的字母、数字或混合字符
  2. 图像绘制:在画布上绘制字符
  3. 干扰处理:添加噪点、线条等干扰元素
  4. 会话存储:将验证码值存储在服务器端会话中
  5. 输出图像:将图像发送到客户端

1.2 VBScript图像处理能力

VBScript本身不具备图像处理能力,但可以通过以下方式实现:

  • ADODB.Stream:处理二进制数据
  • GDI+:通过COM对象调用(需要服务器安装)
  • 纯文本验证码:作为替代方案(安全性较低)

2. 基础实现:纯文本验证码

2.1 简单文本验证码生成

<% ' 文本验证码生成示例 Option Explicit Response.Buffer = True ' 生成随机验证码 Function GenerateCaptchaText(length) Dim chars, i, captchaText chars = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789" ' 排除易混淆字符 Randomize captchaText = "" For i = 1 To length captchaText = captchaText & Mid(chars, Int(Len(chars) * Rnd + 1), 1) Next GenerateCaptchaText = captchaText End Function ' 主处理逻辑 Dim captchaValue, sessionID captchaValue = GenerateCaptchaText(6) sessionID = Session.SessionID ' 存储验证码到Session Session("Captcha_" & sessionID) = captchaValue ' 输出验证码到页面 Response.ContentType = "text/html" Response.Write "<html><body>" Response.Write "<h3>您的验证码是:</h3>" Response.Write "<div style='font-size: 32px; font-weight: bold; color: #333;'>" & captchaValue & "</div>" Response.Write "<p>Session ID: " & sessionID & "</p>" Response.Write "</body></html>" %> 

2.2 验证码验证逻辑

<% ' 验证码验证示例 Option Explicit Dim userInput, storedValue, sessionID, isValid userInput = Request.Form("captcha_input") sessionID = Request.Form("session_id") If sessionID = "" Then Response.Write "错误:缺少Session ID" Response.End End If storedValue = Session("Captcha_" & sessionID) If storedValue = "" Then Response.Write "错误:验证码已过期" Response.End End If ' 不区分大小写验证 isValid = (UCase(Trim(userInput)) = UCase(Trim(storedValue))) If isValid Then Response.Write "验证成功!" Session.Remove "Captcha_" & sessionID ' 清除已使用的验证码 Else Response.Write "验证失败!" End If %> 

3. 高级实现:图像验证码

3.1 使用ADODB.Stream生成简单图像验证码

<% ' 使用ADODB.Stream生成图像验证码 Option Explicit Response.Buffer = True ' 生成随机验证码 Function GenerateCaptchaText(length) Dim chars, i, captchaText, seed chars = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789" Randomize captchaText = "" For i = 1 To length seed = Int(Len(chars) * Rnd + 1) captchaText = captchaText & Mid(chars, seed, 1) Next GenerateCaptchaText = captchaText End Function ' 创建位图数据(简化版,实际需要完整BMP头) Function CreateBMPImage(text) Dim bmpHeader, bmpData, i, charCode Dim width, height, fontSize width = 120 height = 40 fontSize = 20 ' 简化的BMP文件头(1x1像素占位,实际需要完整实现) bmpHeader = "BM" & ChrB(54) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(54) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(40) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(1) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(1) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(1) & ChrB(0) & ChrB(24) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) ' 简化的像素数据(白色背景) bmpData = ChrB(255) & ChrB(255) & ChrB(255) CreateBMPImage = bmpHeader & bmpData End Function ' 主处理 Dim captchaValue, imageStream captchaValue = GenerateCaptchaText(6) Session("Captcha") = captchaValue ' 设置响应头 Response.ContentType = "image/bmp" Response.AddHeader "Content-Disposition", "inline; filename=captcha.bmp" ' 创建流对象 Set imageStream = Server.CreateObject("ADODB.Stream") imageStream.Type = 1 ' adTypeBinary imageStream.Open imageStream.Write CreateBMPImage(captchaValue) imageStream.Position = 0 imageStream.SaveToResponse Response imageStream.Close Set imageStream = Nothing %> 

注意:上述代码是概念演示,实际生成完整BMP图像需要复杂的二进制数据处理。在实际项目中,建议使用COM组件或升级到ASP.NET。

3.2 使用GDI+生成图像验证码(推荐方案)

如果服务器安装了GDI+,可以通过COM调用:

<% ' 使用GDI+生成图像验证码(需要服务器安装GDI+) Option Explicit Response.Buffer = True ' 生成随机验证码 Function GenerateCaptchaText(length) Dim chars, i, captchaText, seed chars = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789" Randomize captchaText = "" For i = 1 To length seed = Int(Len(chars) * Rnd + 1) captchaText = captchaText & Mid(chars, seed, 1) Next GenerateCaptchaText = captchaValue End Function ' 使用GDI+生成图像 Sub GenerateCaptchaImage(text) Dim gdiplus, bitmap, graphics, font, brush, pen, random Dim width, height, i, x, y, angle width = 150 height = 50 ' 创建GDI+对象 Set gdiplus = Server.CreateObject("GDIPlus.GDIPlusStartup") Set bitmap = Server.CreateObject("GDIPlus.Bitmap") Set graphics = Server.CreateObject("GDIPlus.Graphics") Set font = Server.CreateObject("GDIPlus.Font") Set brush = Server.CreateObject("GDIPlus.SolidBrush") Set pen = Server.CreateObject("GDIPlus.Pen") Set random = Server.CreateObject("System.Random") ' 初始化 bitmap.Create width, height graphics.FromImage bitmap ' 填充白色背景 brush.Color = RGB(255, 255, 255) graphics.FillRectangle brush, 0, 0, width, height ' 绘制干扰线 For i = 1 To 8 pen.Color = RGB(random.Next(200), random.Next(200), random.Next(200)) pen.Width = 1 graphics.DrawLine pen, random.Next(width), random.Next(height), random.Next(width), random.Next(height) Next ' 绘制字符(带旋转和偏移) font.Name = "Arial" font.Size = 24 font.Style = 1 ' Bold For i = 1 To Len(text) x = 10 + (i - 1) * 20 y = 25 + random.Next(-5, 5) angle = random.Next(-30, 30) ' 设置随机颜色 brush.Color = RGB(random.Next(50, 150), random.Next(50, 150), random.Next(50, 150)) ' 保存状态,旋转,绘制,恢复状态 graphics.Save() graphics.TranslateTransform x, y graphics.RotateTransform angle graphics.DrawString Mid(text, i, 1), font, brush, 0, 0 graphics.Restore() Next ' 添加噪点 For i = 1 To 50 brush.Color = RGB(random.Next(100), random.Next(100), random.Next(100)) graphics.FillRectangle brush, random.Next(width), random.Next(height), 1, 1 Next ' 输出图像 Response.ContentType = "image/png" bitmap.Save Response, 3 ' PNG格式 ' 清理资源 Set random = Nothing Set pen = Nothing Set brush = Nothing Set font = Nothing Set graphics = Nothing Set bitmap = Nothing Set gdiplus = Nothing End Sub ' 主处理 Dim captchaValue captchaValue = GenerateCaptchaText(6) Session("Captcha") = captchaValue GenerateCaptchaImage captchaValue %> 

3.3 纯ASP实现的图像验证码(无需COM组件)

如果无法使用COM组件,可以使用纯ASP生成简易图像:

<% ' 纯ASP生成图像验证码(使用BMP格式) Option Explicit Response.Buffer = True ' 生成随机验证码 Function GenerateCaptchaText(length) Dim chars, i, captchaText, seed chars = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789" Randomize captchaText = "" For i = 1 To length seed = Int(Len(chars) * Rnd + 1) captchaText = captchaText & Mid(chars, seed, 1) Next GenerateCaptchaText = captchaText End Function ' 生成BMP图像数据 Function GenerateBMP(text) Dim width, height, bmpSize, header, data, i, j, char, charData Dim fontData, fontWidth, fontHeight, x, y, pixel ' 图像尺寸 width = 120 height = 40 fontWidth = 8 fontHeight = 12 ' BMP文件头(54字节) bmpSize = 54 + (width * height * 3) header = "BM" & ChrB(bmpSize Mod 256) & ChrB((bmpSize 256) Mod 256) & ChrB((bmpSize 65536) Mod 256) & ChrB(bmpSize 16777216) header = header & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(54) & ChrB(0) & ChrB(0) & ChrB(0) header = header & ChrB(40) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(width Mod 256) & ChrB(width 256) & ChrB(0) & ChrB(0) header = header & ChrB(height Mod 256) & ChrB(height 256) & ChrB(0) & ChrB(0) & ChrB(1) & ChrB(0) & ChrB(24) & ChrB(0) header = header & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) ' 初始化像素数据(白色背景) data = "" For i = 1 To width * height data = data & ChrB(255) & ChrB(255) & ChrB(255) Next ' 简单的5x7点阵字体 Dim fontMap(36) ' 0-9, A-Z fontMap(0) = Array(0, 0, 0, 0, 0, 0, 0) ' 空 ' 这里简化处理,实际需要完整的点阵字库 ' 绘制字符(简化版,直接在像素数据中修改) Randomize For i = 1 To Len(text) char = Mid(text, i, 1) x = 10 + (i - 1) * 15 y = 15 ' 简单的随机颜色 Dim r, g, b r = Int(100 * Rnd + 50) g = Int(100 * Rnd + 50) b = Int(100 * Rnd + 50) ' 绘制字符(这里简化为矩形,实际需要点阵) For j = 0 To 5 If Int(Rnd * 2) = 1 Then ' 随机绘制 Dim pos pos = ((height - 1 - (y + j)) * width + (x + j)) * 3 + 1 If pos > 54 And pos < Len(data) Then data = Left(data, pos - 1) & ChrB(b) & ChrB(g) & ChrB(r) & Mid(data, pos + 3) End If End If Next Next GenerateBMP = header & data End Function ' 主处理 Dim captchaValue, bmpData captchaValue = GenerateCaptchaText(6) Session("Captcha") = captchaValue Response.ContentType = "image/bmp" Response.AddHeader "Content-Disposition", "inline; filename=captcha.bmp" bmpData = GenerateBMP(captchaValue) Response.BinaryWrite bmpData %> 

重要说明:上述纯ASP图像生成代码是高度简化的,实际应用中需要完整的BMP格式实现和点阵字体库。由于VBScript处理二进制数据的复杂性,强烈建议在生产环境中使用COM组件或升级到ASP.NET。

4. 实战技巧与最佳实践

4.1 安全性增强

4.1.1 防止暴力破解

<% ' 增强安全性的验证码管理 Option Explicit ' 验证码配置 Const CAPTCHA_LENGTH = 6 Const CAPTCHA_EXPIRE = 300 ' 5分钟过期 Const MAX_ATTEMPTS = 3 ' 生成验证码并存储 Function CreateCaptcha() Dim captchaID, captchaValue, expires captchaID = GenerateGUID() captchaValue = GenerateCaptchaText(CAPTCHA_LENGTH) expires = DateAdd("s", CAPTCHA_EXPIRE, Now()) ' 存储到Application对象(带过期时间) Application.Lock Application("Captcha_" & captchaID) = captchaValue & "|" & expires & "|0" Application.Unlock CreateCaptcha = captchaID End Function ' 验证验证码 Function VerifyCaptcha(captchaID, userInput) Dim storedData, parts, value, expires, attempts VerifyCaptcha = False Application.Lock storedData = Application("Captcha_" & captchaID) Application.Unlock If storedData = "" Then Exit Function parts = Split(storedData, "|") If UBound(parts) < 2 Then Exit Function value = parts(0) expires = CDate(parts(1)) attempts = CInt(parts(2)) ' 检查过期 If Now() > expires Then Application.Lock Application.Remove "Captcha_" & captchaID Application.Unlock Exit Function End If ' 检查尝试次数 If attempts >= MAX_ATTEMPTS Then Application.Lock Application.Remove "Captcha_" & captchaID Application.Unlock Exit Function End If ' 验证 If UCase(Trim(userInput)) = UCase(Trim(value)) Then VerifyCaptcha = True Application.Lock Application.Remove "Captcha_" & captchaID Application.Unlock Else ' 更新尝试次数 attempts = attempts + 1 Application.Lock Application("Captcha_" & captchaID) = value & "|" & expires & "|" & attempts Application.Unlock End If End Function ' 辅助函数:生成GUID Function GenerateGUID() Dim guid Set guid = Server.CreateObject("Scriptlet.TypeLib") GenerateGUID = Mid(guid.GUID, 2, 36) Set guid = Nothing End Function ' 辅助函数:生成验证码文本 Function GenerateCaptchaText(length) Dim chars, i, captchaText, seed chars = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789" Randomize captchaText = "" For i = 1 To length seed = Int(Len(chars) * Rnd + 1) captchaText = captchaText & Mid(chars, seed, 1) Next GenerateCaptchaText = captchaText End Function %> 

4.1.2 防止Session固定攻击

<% ' 在登录页面生成验证码时,同时生成新的Session ID If Session("CaptchaGenerated") = "" Then Session.Abandon Session.Start Session("CaptchaGenerated") = True End If %> 

4.2 性能优化

4.2.1 缓存机制

<% ' 使用Application对象缓存验证码配置 If Application("CaptchaConfig") = "" Then Application.Lock Application("CaptchaConfig") = "chars=ABCDEFGHJKLMNPQRSTUVWXYZ23456789|length=6|expire=300" Application.Unlock End If ' 从缓存读取配置 Function GetCaptchaConfig(key) Dim config, parts, i config = Application("CaptchaConfig") parts = Split(config, "|") For i = 0 To UBound(parts) If InStr(parts(i), key & "=") > 0 Then GetCaptchaConfig = Split(parts(i), "=")(1) Exit Function End If Next End Function %> 

4.2.2 异步处理(模拟)

<% ' 使用XMLHTTP模拟异步验证(客户端) ' 前端HTML示例: ' <script> ' function verifyCaptcha() { ' var xhr = new ActiveXObject("Microsoft.XMLHTTP"); ' xhr.open("POST", "verify.asp", false); ' xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); ' xhr.send("captcha=" + document.getElementById('captcha').value); ' return xhr.responseText == "1"; ' } ' </script> %> 

4.3 用户体验优化

4.3.1 提供刷新功能

<% ' 在验证码显示页面添加刷新按钮 Response.Write "<div id='captchaContainer'>" Response.Write "<img src='captcha.asp?id=" & CreateCaptcha() & "' alt='验证码' id='captchaImg' />" Response.Write "<button onclick='refreshCaptcha()'>刷新</button>" Response.Write "</div>" Response.Write "<script>" Response.Write "function refreshCaptcha() {" Response.Write " var img = document.getElementById('captchaImg');" Response.Write " img.src = 'captcha.asp?id=' + new Date().getTime();" Response.Write "}" Response.Write "</script>" %> 

4.3.2 音频验证码(可选)

<% ' 简单的文本转语音提示(需要服务器安装TTS引擎) Function GenerateAudioCaptcha(text) Dim sapi Set sapi = Server.CreateObject("SAPI.SpVoice") sapi.Speak "您的验证码是:" & text Set sapi = Nothing End Function %> 

5. 完整实战案例:登录页面集成

5.1 登录页面(login.asp)

<% Option Explicit Response.Buffer = True ' 生成验证码ID Dim captchaID captchaID = CreateCaptcha() %> <!DOCTYPE html> <html> <head> <title>用户登录</title> <style> body { font-family: Arial, sans-serif; margin: 40px; } .login-form { width: 300px; margin: 0 auto; } .form-group { margin-bottom: 15px; } label { display: block; margin-bottom: 5px; font-weight: bold; } input[type="text"], input[type="password"] { width: 100%; padding: 8px; } .captcha-container { display: flex; align-items: center; gap: 10px; } .captcha-img { border: 1px solid #ccc; } .error { color: red; font-size: 12px; } </style> </head> <body> <div class="login-form"> <h2>用户登录</h2> <form method="post" action="login_process.asp" onsubmit="return validateForm()"> <div class="form-group"> <label>用户名:</label> <input type="text" name="username" id="username" required> </div> <div class="form-group"> <label>密码:</label> <input type="password" name="password" id="password" required> </div> <div class="form-group"> <label>验证码:</label> <div class="captcha-container"> <img src="captcha.asp?id=<%=captchaID%>" alt="验证码" id="captchaImg" class="captcha-img"> <button type="button" onclick="refreshCaptcha()">刷新</button> </div> <input type="text" name="captcha_input" id="captcha_input" placeholder="请输入验证码" required> <input type="hidden" name="captcha_id" value="<%=captchaID%>"> </div> <div class="form-group"> <button type="submit">登录</button> </div> <div id="errorMsg" class="error"></div> </form> </div> <script> function refreshCaptcha() { var img = document.getElementById('captchaImg'); img.src = 'captcha.asp?id=' + new Date().getTime(); } function validateForm() { var userInput = document.getElementById('captcha_input').value; if (userInput.length != 6) { document.getElementById('errorMsg').innerText = '验证码必须为6位字符'; return false; } return true; } </script> </body> </html> 

5.2 验证码生成页面(captcha.asp)

<% Option Explicit Response.Buffer = True ' 包含核心函数 %> <!--#include file="captcha_functions.asp"--> <% Dim captchaID, captchaValue, bmpData ' 获取验证码ID captchaID = Request.QueryString("id") If captchaID = "" Then Response.Write "错误:缺少验证码ID" Response.End End If ' 生成验证码值 captchaValue = GenerateCaptchaText(6) ' 存储到Application(带过期时间) Application.Lock Application("Captcha_" & captchaID) = captchaValue & "|" & DateAdd("s", 300, Now()) & "|0" Application.Unlock ' 生成图像 Response.ContentType = "image/bmp" Response.AddHeader "Content-Disposition", "inline; filename=captcha.bmp" bmpData = GenerateBMP(captchaValue) Response.BinaryWrite bmpData %> 

5.3 验证处理页面(login_process.asp)

<% Option Explicit Response.Buffer = True ' 包含核心函数 %> <!--#include file="captcha_functions.asp"--> <% Dim username, password, captchaID, captchaInput, result username = Request.Form("username") password = Request.Form("password") captchaID = Request.Form("captcha_id") captchaInput = Request.Form("captcha_input") ' 验证输入 If username = "" Or password = "" Or captchaID = "" Or captchaInput = "" Then Response.Redirect "login.asp?error=missing" Response.End End If ' 验证验证码 If VerifyCaptcha(captchaID, captchaInput) Then ' 验证码正确,进行用户验证 ' 这里可以连接数据库验证用户名和密码 If ValidateUser(username, password) Then Session("UserID") = username Session("LoginTime") = Now() Response.Redirect "welcome.asp" Else Response.Redirect "login.asp?error=invalid_user" End If Else Response.Redirect "login.asp?error=invalid_captcha" End If Function ValidateUser(username, password) ' 模拟用户验证(实际应查询数据库) If username = "admin" And password = "password123" Then ValidateUser = True Else ValidateUser = False End If End Function %> 

5.4 核心函数库(captcha_functions.asp)

<% ' 验证码核心函数库 Option Explicit Const CAPTCHA_EXPIRE = 300 Const MAX_ATTEMPTS = 3 ' 生成验证码文本 Function GenerateCaptchaText(length) Dim chars, i, captchaText, seed chars = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789" Randomize captchaText = "" For i = 1 To length seed = Int(Len(chars) * Rnd + 1) captchaText = captchaText & Mid(chars, seed, 1) Next GenerateCaptchaText = captchaText End Function ' 生成BMP图像 Function GenerateBMP(text) Dim width, height, bmpSize, header, data, i, j, char, x, y Dim r, g, b, pos width = 120 height = 40 ' BMP文件头 bmpSize = 54 + (width * height * 3) header = "BM" & ChrB(bmpSize Mod 256) & ChrB((bmpSize 256) Mod 256) & ChrB((bmpSize 65536) Mod 256) & ChrB(bmpSize 16777216) header = header & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(54) & ChrB(0) & ChrB(0) & ChrB(0) header = header & ChrB(40) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(width Mod 256) & ChrB(width 256) & ChrB(0) & ChrB(0) header = header & ChrB(height Mod 256) & ChrB(height 256) & ChrB(0) & ChrB(0) & ChrB(1) & ChrB(0) & ChrB(24) & ChrB(0) header = header & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) ' 初始化白色背景 data = "" For i = 1 To width * height data = data & ChrB(255) & ChrB(255) & ChrB(255) Next ' 绘制字符(简化版) Randomize For i = 1 To Len(text) char = Mid(text, i, 1) x = 10 + (i - 1) * 15 y = 15 ' 随机颜色 r = Int(100 * Rnd + 50) g = Int(100 * Rnd + 50) b = Int(100 * Rnd + 50) ' 绘制字符(简化为随机点) For j = 0 To 5 If Int(Rnd * 2) = 1 Then pos = ((height - 1 - (y + j)) * width + (x + j)) * 3 + 1 If pos > 54 And pos < Len(data) Then data = Left(data, pos - 1) & ChrB(b) & ChrB(g) & ChrB(r) & Mid(data, pos + 3) End If End If Next Next GenerateBMP = header & data End Function ' 创建验证码ID Function CreateCaptcha() Dim guid Set guid = Server.CreateObject("Scriptlet.TypeLib") CreateCaptcha = Mid(guid.GUID, 2, 36) Set guid = Nothing End Function ' 验证验证码 Function VerifyCaptcha(captchaID, userInput) Dim storedData, parts, value, expires, attempts VerifyCaptcha = False Application.Lock storedData = Application("Captcha_" & captchaID) Application.Unlock If storedData = "" Then Exit Function parts = Split(storedData, "|") If UBound(parts) < 2 Then Exit Function value = parts(0) expires = CDate(parts(1)) attempts = CInt(parts(2)) ' 检查过期 If Now() > expires Then Application.Lock Application.Remove "Captcha_" & captchaID Application.Unlock Exit Function End If ' 检查尝试次数 If attempts >= MAX_ATTEMPTS Then Application.Lock Application.Remove "Captcha_" & captchaID Application.Unlock Exit Function End If ' 验证 If UCase(Trim(userInput)) = UCase(Trim(value)) Then VerifyCaptcha = True Application.Lock Application.Remove "Captcha_" & captchaID Application.Unlock Else attempts = attempts + 1 Application.Lock Application("Captcha_" & captchaID) = value & "|" & expires & "|" & attempts Application.Unlock End If End Function %> 

6. 常见问题与解决方案

6.1 图像显示问题

问题:生成的图像无法显示或显示乱码 解决方案

<% ' 确保响应头正确设置 Response.ContentType = "image/bmp" Response.AddHeader "Content-Disposition", "inline; filename=captcha.bmp" ' 确保没有其他输出 Response.Buffer = True Response.Clear ' 检查BMP格式是否正确 ' 使用在线BMP验证工具检查生成的图像 %> 

6.2 Session过期问题

问题:验证码在提交前已过期 解决方案

<% ' 在生成验证码时返回过期时间给客户端 Response.Write "<script>var captchaExpires = " & CAPTCHA_EXPIRE & ";</script>" ' 客户端倒计时提醒 Response.Write "<div id='captchaTimer'></div>" Response.Write "<script>" Response.Write "function updateTimer() {" Response.Write " var timer = document.getElementById('captchaTimer');" Response.Write " if (captchaExpires > 0) {" Response.Write " captchaExpires--;" Response.Write " timer.innerText = '验证码将在' + captchaExpires + '秒后过期';" Response.Write " setTimeout(updateTimer, 1000);" Response.Write " } else {" Response.Write " timer.innerText = '验证码已过期,请刷新';" Response.Write " }" Response.Write "}" Response.Write "updateTimer();" Response.Write "</script>" %> 

6.3 并发访问问题

问题:Application对象锁定导致性能瓶颈 解决方案

<% ' 使用Session替代Application(减少锁定) ' 或使用数据库存储验证码 Function StoreCaptchaInDB(captchaID, value) Dim conn, cmd Set conn = Server.CreateObject("ADODB.Connection") conn.Open "your_connection_string" Set cmd = Server.CreateObject("ADODB.Command") cmd.ActiveConnection = conn cmd.CommandText = "INSERT INTO CaptchaValues (CaptchaID, Value, Expires, Attempts) VALUES (?, ?, ?, 0)" cmd.Parameters.Append cmd.CreateParameter("@id", 200, 1, 50, captchaID) cmd.Parameters.Append cmd.CreateParameter("@value", 200, 1, 10, value) cmd.Parameters.Append cmd.CreateParameter("@expires", 7, 1, , DateAdd("s", CAPTCHA_EXPIRE, Now())) cmd.Execute conn.Close Set cmd = Nothing Set conn = Nothing End Function %> 

7. 总结与展望

7.1 关键要点回顾

  1. VBScript验证码生成的核心挑战:缺乏原生图像处理能力,需要依赖COM组件或纯文本方案
  2. 安全优先:必须实现过期时间、尝试次数限制、防止暴力破解
  3. 性能考虑:合理使用Application/Session对象,避免过度锁定
  4. 用户体验:提供刷新功能、清晰的错误提示、适当的过期提醒

7.2 技术选型建议

场景推荐方案优点缺点
维护遗留系统纯文本验证码实现简单,无需额外组件安全性较低
内部企业应用简易图像验证码平衡安全性与复杂度需要COM组件支持
高安全要求升级到ASP.NET功能强大,安全性高需要迁移成本

7.3 未来发展方向

虽然VBScript在现代Web开发中已逐渐淘汰,但在特定场景下仍有其价值。建议:

  • 短期:优化现有VBScript验证码系统,增强安全性
  • 中期:逐步迁移到ASP.NET或PHP等现代技术栈
  • 长期:考虑使用云验证码服务(如Google reCAPTCHA)替代自研方案

通过本文的详细讲解和实战案例,您应该能够根据实际需求选择合适的VBScript验证码生成方案,并掌握相关的安全防护和性能优化技巧。在实际部署时,请务必根据具体环境调整代码,并进行充分的安全测试。# VBScript网页验证码生成方法详解与实战技巧分享

引言:验证码在Web安全中的重要性

验证码(CAPTCHA)是”Completely Automated Public Turing test to tell Computers and Humans Apart”的缩写,即全自动区分计算机和人类的公开图灵测试。在Web应用中,验证码是防止恶意机器人攻击、垃圾注册、暴力破解等安全威胁的重要防线。

虽然现代Web开发更多使用PHP、Python、Node.js等后端技术,但在某些特定场景下(如遗留系统维护、企业内部应用、ASP经典环境等),VBScript仍然发挥着重要作用。本文将详细介绍如何使用VBScript生成网页验证码,包括基础原理、代码实现、优化技巧和实战案例。

1. VBScript验证码生成基础原理

1.1 验证码生成流程

验证码生成的核心流程包括:

  1. 随机字符串生成:创建随机的字母、数字或混合字符
  2. 图像绘制:在画布上绘制字符
  3. 干扰处理:添加噪点、线条等干扰元素
  4. 会话存储:将验证码值存储在服务器端会话中
  5. 输出图像:将图像发送到客户端

1.2 VBScript图像处理能力

VBScript本身不具备图像处理能力,但可以通过以下方式实现:

  • ADODB.Stream:处理二进制数据
  • GDI+:通过COM对象调用(需要服务器安装)
  • 纯文本验证码:作为替代方案(安全性较低)

2. 基础实现:纯文本验证码

2.1 简单文本验证码生成

<% ' 文本验证码生成示例 Option Explicit Response.Buffer = True ' 生成随机验证码 Function GenerateCaptchaText(length) Dim chars, i, captchaText chars = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789" ' 排除易混淆字符 Randomize captchaText = "" For i = 1 To length captchaText = captchaText & Mid(chars, Int(Len(chars) * Rnd + 1), 1) Next GenerateCaptchaText = captchaText End Function ' 主处理逻辑 Dim captchaValue, sessionID captchaValue = GenerateCaptchaText(6) sessionID = Session.SessionID ' 存储验证码到Session Session("Captcha_" & sessionID) = captchaValue ' 输出验证码到页面 Response.ContentType = "text/html" Response.Write "<html><body>" Response.Write "<h3>您的验证码是:</h3>" Response.Write "<div style='font-size: 32px; font-weight: bold; color: #333;'>" & captchaValue & "</div>" Response.Write "<p>Session ID: " & sessionID & "</p>" Response.Write "</body></html>" %> 

2.2 验证码验证逻辑

<% ' 验证码验证示例 Option Explicit Dim userInput, storedValue, sessionID, isValid userInput = Request.Form("captcha_input") sessionID = Request.Form("session_id") If sessionID = "" Then Response.Write "错误:缺少Session ID" Response.End End If storedValue = Session("Captcha_" & sessionID) If storedValue = "" Then Response.Write "错误:验证码已过期" Response.End End If ' 不区分大小写验证 isValid = (UCase(Trim(userInput)) = UCase(Trim(storedValue))) If isValid Then Response.Write "验证成功!" Session.Remove "Captcha_" & sessionID ' 清除已使用的验证码 Else Response.Write "验证失败!" End If %> 

3. 高级实现:图像验证码

3.1 使用ADODB.Stream生成简单图像验证码

<% ' 使用ADODB.Stream生成图像验证码 Option Explicit Response.Buffer = True ' 生成随机验证码 Function GenerateCaptchaText(length) Dim chars, i, captchaText, seed chars = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789" Randomize captchaText = "" For i = 1 To length seed = Int(Len(chars) * Rnd + 1) captchaText = captchaText & Mid(chars, seed, 1) Next GenerateCaptchaText = captchaText End Function ' 创建位图数据(简化版,实际需要完整BMP头) Function CreateBMPImage(text) Dim bmpHeader, bmpData, i, charCode Dim width, height, fontSize width = 120 height = 40 fontSize = 20 ' 简化的BMP文件头(1x1像素占位,实际需要完整实现) bmpHeader = "BM" & ChrB(54) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(54) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(40) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(1) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(1) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(1) & ChrB(0) & ChrB(24) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) ' 简化的像素数据(白色背景) bmpData = ChrB(255) & ChrB(255) & ChrB(255) CreateBMPImage = bmpHeader & bmpData End Function ' 主处理 Dim captchaValue, imageStream captchaValue = GenerateCaptchaText(6) Session("Captcha") = captchaValue ' 设置响应头 Response.ContentType = "image/bmp" Response.AddHeader "Content-Disposition", "inline; filename=captcha.bmp" ' 创建流对象 Set imageStream = Server.CreateObject("ADODB.Stream") imageStream.Type = 1 ' adTypeBinary imageStream.Open imageStream.Write CreateBMPImage(captchaValue) imageStream.Position = 0 imageStream.SaveToResponse Response imageStream.Close Set imageStream = Nothing %> 

注意:上述代码是概念演示,实际生成完整BMP图像需要复杂的二进制数据处理。在实际项目中,建议使用COM组件或升级到ASP.NET。

3.2 使用GDI+生成图像验证码(推荐方案)

如果服务器安装了GDI+,可以通过COM调用:

<% ' 使用GDI+生成图像验证码(需要服务器安装GDI+) Option Explicit Response.Buffer = True ' 生成随机验证码 Function GenerateCaptchaText(length) Dim chars, i, captchaText, seed chars = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789" Randomize captchaText = "" For i = 1 To length seed = Int(Len(chars) * Rnd + 1) captchaText = captchaText & Mid(chars, seed, 1) Next GenerateCaptchaText = captchaValue End Function ' 使用GDI+生成图像 Sub GenerateCaptchaImage(text) Dim gdiplus, bitmap, graphics, font, brush, pen, random Dim width, height, i, x, y, angle width = 150 height = 50 ' 创建GDI+对象 Set gdiplus = Server.CreateObject("GDIPlus.GDIPlusStartup") Set bitmap = Server.CreateObject("GDIPlus.Bitmap") Set graphics = Server.CreateObject("GDIPlus.Graphics") Set font = Server.CreateObject("GDIPlus.Font") Set brush = Server.CreateObject("GDIPlus.SolidBrush") Set pen = Server.CreateObject("GDIPlus.Pen") Set random = Server.CreateObject("System.Random") ' 初始化 bitmap.Create width, height graphics.FromImage bitmap ' 填充白色背景 brush.Color = RGB(255, 255, 255) graphics.FillRectangle brush, 0, 0, width, height ' 绘制干扰线 For i = 1 To 8 pen.Color = RGB(random.Next(200), random.Next(200), random.Next(200)) pen.Width = 1 graphics.DrawLine pen, random.Next(width), random.Next(height), random.Next(width), random.Next(height) Next ' 绘制字符(带旋转和偏移) font.Name = "Arial" font.Size = 24 font.Style = 1 ' Bold For i = 1 To Len(text) x = 10 + (i - 1) * 20 y = 25 + random.Next(-5, 5) angle = random.Next(-30, 30) ' 设置随机颜色 brush.Color = RGB(random.Next(50, 150), random.Next(50, 150), random.Next(50, 150)) ' 保存状态,旋转,绘制,恢复状态 graphics.Save() graphics.TranslateTransform x, y graphics.RotateTransform angle graphics.DrawString Mid(text, i, 1), font, brush, 0, 0 graphics.Restore() Next ' 添加噪点 For i = 1 To 50 brush.Color = RGB(random.Next(100), random.Next(100), random.Next(100)) graphics.FillRectangle brush, random.Next(width), random.Next(height), 1, 1 Next ' 输出图像 Response.ContentType = "image/png" bitmap.Save Response, 3 ' PNG格式 ' 清理资源 Set random = Nothing Set pen = Nothing Set brush = Nothing Set font = Nothing Set graphics = Nothing Set bitmap = Nothing Set gdiplus = Nothing End Sub ' 主处理 Dim captchaValue captchaValue = GenerateCaptchaText(6) Session("Captcha") = captchaValue GenerateCaptchaImage captchaValue %> 

3.3 纯ASP实现的图像验证码(无需COM组件)

如果无法使用COM组件,可以使用纯ASP生成简易图像:

<% ' 纯ASP生成图像验证码(使用BMP格式) Option Explicit Response.Buffer = True ' 生成随机验证码 Function GenerateCaptchaText(length) Dim chars, i, captchaText, seed chars = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789" Randomize captchaText = "" For i = 1 To length seed = Int(Len(chars) * Rnd + 1) captchaText = captchaText & Mid(chars, seed, 1) Next GenerateCaptchaText = captchaText End Function ' 生成BMP图像数据 Function GenerateBMP(text) Dim width, height, bmpSize, header, data, i, j, char, charData Dim fontData, fontWidth, fontHeight, x, y, pixel ' 图像尺寸 width = 120 height = 40 fontWidth = 8 fontHeight = 12 ' BMP文件头(54字节) bmpSize = 54 + (width * height * 3) header = "BM" & ChrB(bmpSize Mod 256) & ChrB((bmpSize 256) Mod 256) & ChrB((bmpSize 65536) Mod 256) & ChrB(bmpSize 16777216) header = header & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(54) & ChrB(0) & ChrB(0) & ChrB(0) header = header & ChrB(40) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(width Mod 256) & ChrB(width 256) & ChrB(0) & ChrB(0) header = header & ChrB(height Mod 256) & ChrB(height 256) & ChrB(0) & ChrB(0) & ChrB(1) & ChrB(0) & ChrB(24) & ChrB(0) header = header & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) ' 初始化像素数据(白色背景) data = "" For i = 1 To width * height data = data & ChrB(255) & ChrB(255) & ChrB(255) Next ' 简单的5x7点阵字体 Dim fontMap(36) ' 0-9, A-Z fontMap(0) = Array(0, 0, 0, 0, 0, 0, 0) ' 空 ' 这里简化处理,实际需要完整的点阵字库 ' 绘制字符(简化版,直接在像素数据中修改) Randomize For i = 1 To Len(text) char = Mid(text, i, 1) x = 10 + (i - 1) * 15 y = 15 ' 简单的随机颜色 Dim r, g, b r = Int(100 * Rnd + 50) g = Int(100 * Rnd + 50) b = Int(100 * Rnd + 50) ' 绘制字符(这里简化为矩形,实际需要点阵) For j = 0 To 5 If Int(Rnd * 2) = 1 Then ' 随机绘制 Dim pos pos = ((height - 1 - (y + j)) * width + (x + j)) * 3 + 1 If pos > 54 And pos < Len(data) Then data = Left(data, pos - 1) & ChrB(b) & ChrB(g) & ChrB(r) & Mid(data, pos + 3) End If End If Next Next GenerateBMP = header & data End Function ' 主处理 Dim captchaValue, bmpData captchaValue = GenerateCaptchaText(6) Session("Captcha") = captchaValue Response.ContentType = "image/bmp" Response.AddHeader "Content-Disposition", "inline; filename=captcha.bmp" bmpData = GenerateBMP(captchaValue) Response.BinaryWrite bmpData %> 

重要说明:上述纯ASP图像生成代码是高度简化的,实际应用中需要完整的BMP格式实现和点阵字体库。由于VBScript处理二进制数据的复杂性,强烈建议在生产环境中使用COM组件或升级到ASP.NET。

4. 实战技巧与最佳实践

4.1 安全性增强

4.1.1 防止暴力破解

<% ' 增强安全性的验证码管理 Option Explicit ' 验证码配置 Const CAPTCHA_LENGTH = 6 Const CAPTCHA_EXPIRE = 300 ' 5分钟过期 Const MAX_ATTEMPTS = 3 ' 生成验证码并存储 Function CreateCaptcha() Dim captchaID, captchaValue, expires captchaID = GenerateGUID() captchaValue = GenerateCaptchaText(CAPTCHA_LENGTH) expires = DateAdd("s", CAPTCHA_EXPIRE, Now()) ' 存储到Application对象(带过期时间) Application.Lock Application("Captcha_" & captchaID) = captchaValue & "|" & expires & "|0" Application.Unlock CreateCaptcha = captchaID End Function ' 验证验证码 Function VerifyCaptcha(captchaID, userInput) Dim storedData, parts, value, expires, attempts VerifyCaptcha = False Application.Lock storedData = Application("Captcha_" & captchaID) Application.Unlock If storedData = "" Then Exit Function parts = Split(storedData, "|") If UBound(parts) < 2 Then Exit Function value = parts(0) expires = CDate(parts(1)) attempts = CInt(parts(2)) ' 检查过期 If Now() > expires Then Application.Lock Application.Remove "Captcha_" & captchaID Application.Unlock Exit Function End If ' 检查尝试次数 If attempts >= MAX_ATTEMPTS Then Application.Lock Application.Remove "Captcha_" & captchaID Application.Unlock Exit Function End If ' 验证 If UCase(Trim(userInput)) = UCase(Trim(value)) Then VerifyCaptcha = True Application.Lock Application.Remove "Captcha_" & captchaID Application.Unlock Else ' 更新尝试次数 attempts = attempts + 1 Application.Lock Application("Captcha_" & captchaID) = value & "|" & expires & "|" & attempts Application.Unlock End If End Function ' 辅助函数:生成GUID Function GenerateGUID() Dim guid Set guid = Server.CreateObject("Scriptlet.TypeLib") GenerateGUID = Mid(guid.GUID, 2, 36) Set guid = Nothing End Function ' 辅助函数:生成验证码文本 Function GenerateCaptchaText(length) Dim chars, i, captchaText, seed chars = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789" Randomize captchaText = "" For i = 1 To length seed = Int(Len(chars) * Rnd + 1) captchaText = captchaText & Mid(chars, seed, 1) Next GenerateCaptchaText = captchaText End Function %> 

4.1.2 防止Session固定攻击

<% ' 在登录页面生成验证码时,同时生成新的Session ID If Session("CaptchaGenerated") = "" Then Session.Abandon Session.Start Session("CaptchaGenerated") = True End If %> 

4.2 性能优化

4.2.1 缓存机制

<% ' 使用Application对象缓存验证码配置 If Application("CaptchaConfig") = "" Then Application.Lock Application("CaptchaConfig") = "chars=ABCDEFGHJKLMNPQRSTUVWXYZ23456789|length=6|expire=300" Application.Unlock End If ' 从缓存读取配置 Function GetCaptchaConfig(key) Dim config, parts, i config = Application("CaptchaConfig") parts = Split(config, "|") For i = 0 To UBound(parts) If InStr(parts(i), key & "=") > 0 Then GetCaptchaConfig = Split(parts(i), "=")(1) Exit Function End If Next End Function %> 

4.2.2 异步处理(模拟)

<% ' 使用XMLHTTP模拟异步验证(客户端) ' 前端HTML示例: ' <script> ' function verifyCaptcha() { ' var xhr = new ActiveXObject("Microsoft.XMLHTTP"); ' xhr.open("POST", "verify.asp", false); ' xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); ' xhr.send("captcha=" + document.getElementById('captcha').value); ' return xhr.responseText == "1"; ' } ' </script> %> 

4.3 用户体验优化

4.3.1 提供刷新功能

<% ' 在验证码显示页面添加刷新按钮 Response.Write "<div id='captchaContainer'>" Response.Write "<img src='captcha.asp?id=" & CreateCaptcha() & "' alt='验证码' id='captchaImg' />" Response.Write "<button onclick='refreshCaptcha()'>刷新</button>" Response.Write "</div>" Response.Write "<script>" Response.Write "function refreshCaptcha() {" Response.Write " var img = document.getElementById('captchaImg');" Response.Write " img.src = 'captcha.asp?id=' + new Date().getTime();" Response.Write "}" Response.Write "</script>" %> 

4.3.2 音频验证码(可选)

<% ' 简单的文本转语音提示(需要服务器安装TTS引擎) Function GenerateAudioCaptcha(text) Dim sapi Set sapi = Server.CreateObject("SAPI.SpVoice") sapi.Speak "您的验证码是:" & text Set sapi = Nothing End Function %> 

5. 完整实战案例:登录页面集成

5.1 登录页面(login.asp)

<% Option Explicit Response.Buffer = True ' 生成验证码ID Dim captchaID captchaID = CreateCaptcha() %> <!DOCTYPE html> <html> <head> <title>用户登录</title> <style> body { font-family: Arial, sans-serif; margin: 40px; } .login-form { width: 300px; margin: 0 auto; } .form-group { margin-bottom: 15px; } label { display: block; margin-bottom: 5px; font-weight: bold; } input[type="text"], input[type="password"] { width: 100%; padding: 8px; } .captcha-container { display: flex; align-items: center; gap: 10px; } .captcha-img { border: 1px solid #ccc; } .error { color: red; font-size: 12px; } </style> </head> <body> <div class="login-form"> <h2>用户登录</h2> <form method="post" action="login_process.asp" onsubmit="return validateForm()"> <div class="form-group"> <label>用户名:</label> <input type="text" name="username" id="username" required> </div> <div class="form-group"> <label>密码:</label> <input type="password" name="password" id="password" required> </div> <div class="form-group"> <label>验证码:</label> <div class="captcha-container"> <img src="captcha.asp?id=<%=captchaID%>" alt="验证码" id="captchaImg" class="captcha-img"> <button type="button" onclick="refreshCaptcha()">刷新</button> </div> <input type="text" name="captcha_input" id="captcha_input" placeholder="请输入验证码" required> <input type="hidden" name="captcha_id" value="<%=captchaID%>"> </div> <div class="form-group"> <button type="submit">登录</button> </div> <div id="errorMsg" class="error"></div> </form> </div> <script> function refreshCaptcha() { var img = document.getElementById('captchaImg'); img.src = 'captcha.asp?id=' + new Date().getTime(); } function validateForm() { var userInput = document.getElementById('captcha_input').value; if (userInput.length != 6) { document.getElementById('errorMsg').innerText = '验证码必须为6位字符'; return false; } return true; } </script> </body> </html> 

5.2 验证码生成页面(captcha.asp)

<% Option Explicit Response.Buffer = True ' 包含核心函数 %> <!--#include file="captcha_functions.asp"--> <% Dim captchaID, captchaValue, bmpData ' 获取验证码ID captchaID = Request.QueryString("id") If captchaID = "" Then Response.Write "错误:缺少验证码ID" Response.End End If ' 生成验证码值 captchaValue = GenerateCaptchaText(6) ' 存储到Application(带过期时间) Application.Lock Application("Captcha_" & captchaID) = captchaValue & "|" & DateAdd("s", 300, Now()) & "|0" Application.Unlock ' 生成图像 Response.ContentType = "image/bmp" Response.AddHeader "Content-Disposition", "inline; filename=captcha.bmp" bmpData = GenerateBMP(captchaValue) Response.BinaryWrite bmpData %> 

5.3 验证处理页面(login_process.asp)

<% Option Explicit Response.Buffer = True ' 包含核心函数 %> <!--#include file="captcha_functions.asp"--> <% Dim username, password, captchaID, captchaInput, result username = Request.Form("username") password = Request.Form("password") captchaID = Request.Form("captcha_id") captchaInput = Request.Form("captcha_input") ' 验证输入 If username = "" Or password = "" Or captchaID = "" Or captchaInput = "" Then Response.Redirect "login.asp?error=missing" Response.End End If ' 验证验证码 If VerifyCaptcha(captchaID, captchaInput) Then ' 验证码正确,进行用户验证 ' 这里可以连接数据库验证用户名和密码 If ValidateUser(username, password) Then Session("UserID") = username Session("LoginTime") = Now() Response.Redirect "welcome.asp" Else Response.Redirect "login.asp?error=invalid_user" End If Else Response.Redirect "login.asp?error=invalid_captcha" End If Function ValidateUser(username, password) ' 模拟用户验证(实际应查询数据库) If username = "admin" And password = "password123" Then ValidateUser = True Else ValidateUser = False End If End Function %> 

5.4 核心函数库(captcha_functions.asp)

<% ' 验证码核心函数库 Option Explicit Const CAPTCHA_EXPIRE = 300 Const MAX_ATTEMPTS = 3 ' 生成验证码文本 Function GenerateCaptchaText(length) Dim chars, i, captchaText, seed chars = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789" Randomize captchaText = "" For i = 1 To length seed = Int(Len(chars) * Rnd + 1) captchaText = captchaText & Mid(chars, seed, 1) Next GenerateCaptchaText = captchaText End Function ' 生成BMP图像 Function GenerateBMP(text) Dim width, height, bmpSize, header, data, i, j, char, x, y Dim r, g, b, pos width = 120 height = 40 ' BMP文件头 bmpSize = 54 + (width * height * 3) header = "BM" & ChrB(bmpSize Mod 256) & ChrB((bmpSize 256) Mod 256) & ChrB((bmpSize 65536) Mod 256) & ChrB(bmpSize 16777216) header = header & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(54) & ChrB(0) & ChrB(0) & ChrB(0) header = header & ChrB(40) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(width Mod 256) & ChrB(width 256) & ChrB(0) & ChrB(0) header = header & ChrB(height Mod 256) & ChrB(height 256) & ChrB(0) & ChrB(0) & ChrB(1) & ChrB(0) & ChrB(24) & ChrB(0) header = header & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) ' 初始化白色背景 data = "" For i = 1 To width * height data = data & ChrB(255) & ChrB(255) & ChrB(255) Next ' 绘制字符(简化版) Randomize For i = 1 To Len(text) char = Mid(text, i, 1) x = 10 + (i - 1) * 15 y = 15 ' 随机颜色 r = Int(100 * Rnd + 50) g = Int(100 * Rnd + 50) b = Int(100 * Rnd + 50) ' 绘制字符(简化为随机点) For j = 0 To 5 If Int(Rnd * 2) = 1 Then pos = ((height - 1 - (y + j)) * width + (x + j)) * 3 + 1 If pos > 54 And pos < Len(data) Then data = Left(data, pos - 1) & ChrB(b) & ChrB(g) & ChrB(r) & Mid(data, pos + 3) End If End If Next Next GenerateBMP = header & data End Function ' 创建验证码ID Function CreateCaptcha() Dim guid Set guid = Server.CreateObject("Scriptlet.TypeLib") CreateCaptcha = Mid(guid.GUID, 2, 36) Set guid = Nothing End Function ' 验证验证码 Function VerifyCaptcha(captchaID, userInput) Dim storedData, parts, value, expires, attempts VerifyCaptcha = False Application.Lock storedData = Application("Captcha_" & captchaID) Application.Unlock If storedData = "" Then Exit Function parts = Split(storedData, "|") If UBound(parts) < 2 Then Exit Function value = parts(0) expires = CDate(parts(1)) attempts = CInt(parts(2)) ' 检查过期 If Now() > expires Then Application.Lock Application.Remove "Captcha_" & captchaID Application.Unlock Exit Function End If ' 检查尝试次数 If attempts >= MAX_ATTEMPTS Then Application.Lock Application.Remove "Captcha_" & captchaID Application.Unlock Exit Function End If ' 验证 If UCase(Trim(userInput)) = UCase(Trim(value)) Then VerifyCaptcha = True Application.Lock Application.Remove "Captcha_" & captchaID Application.Unlock Else attempts = attempts + 1 Application.Lock Application("Captcha_" & captchaID) = value & "|" & expires & "|" & attempts Application.Unlock End If End Function %> 

6. 常见问题与解决方案

6.1 图像显示问题

问题:生成的图像无法显示或显示乱码 解决方案

<% ' 确保响应头正确设置 Response.ContentType = "image/bmp" Response.AddHeader "Content-Disposition", "inline; filename=captcha.bmp" ' 确保没有其他输出 Response.Buffer = True Response.Clear ' 检查BMP格式是否正确 ' 使用在线BMP验证工具检查生成的图像 %> 

6.2 Session过期问题

问题:验证码在提交前已过期 解决方案

<% ' 在生成验证码时返回过期时间给客户端 Response.Write "<script>var captchaExpires = " & CAPTCHA_EXPIRE & ";</script>" ' 客户端倒计时提醒 Response.Write "<div id='captchaTimer'></div>" Response.Write "<script>" Response.Write "function updateTimer() {" Response.Write " var timer = document.getElementById('captchaTimer');" Response.Write " if (captchaExpires > 0) {" Response.Write " captchaExpires--;" Response.Write " timer.innerText = '验证码将在' + captchaExpires + '秒后过期';" Response.Write " setTimeout(updateTimer, 1000);" Response.Write " } else {" Response.Write " timer.innerText = '验证码已过期,请刷新';" Response.Write " }" Response.Write "}" Response.Write "updateTimer();" Response.Write "</script>" %> 

6.3 并发访问问题

问题:Application对象锁定导致性能瓶颈 解决方案

<% ' 使用Session替代Application(减少锁定) ' 或使用数据库存储验证码 Function StoreCaptchaInDB(captchaID, value) Dim conn, cmd Set conn = Server.CreateObject("ADODB.Connection") conn.Open "your_connection_string" Set cmd = Server.CreateObject("ADODB.Command") cmd.ActiveConnection = conn cmd.CommandText = "INSERT INTO CaptchaValues (CaptchaID, Value, Expires, Attempts) VALUES (?, ?, ?, 0)" cmd.Parameters.Append cmd.CreateParameter("@id", 200, 1, 50, captchaID) cmd.Parameters.Append cmd.CreateParameter("@value", 200, 1, 10, value) cmd.Parameters.Append cmd.CreateParameter("@expires", 7, 1, , DateAdd("s", CAPTCHA_EXPIRE, Now())) cmd.Execute conn.Close Set cmd = Nothing Set conn = Nothing End Function %> 

7. 总结与展望

7.1 关键要点回顾

  1. VBScript验证码生成的核心挑战:缺乏原生图像处理能力,需要依赖COM组件或纯文本方案
  2. 安全优先:必须实现过期时间、尝试次数限制、防止暴力破解
  3. 性能考虑:合理使用Application/Session对象,避免过度锁定
  4. 用户体验:提供刷新功能、清晰的错误提示、适当的过期提醒

7.2 技术选型建议

场景推荐方案优点缺点
维护遗留系统纯文本验证码实现简单,无需额外组件安全性较低
内部企业应用简易图像验证码平衡安全性与复杂度需要COM组件支持
高安全要求升级到ASP.NET功能强大,安全性高需要迁移成本

7.3 未来发展方向

虽然VBScript在现代Web开发中已逐渐淘汰,但在特定场景下仍有其价值。建议:

  • 短期:优化现有VBScript验证码系统,增强安全性
  • 中期:逐步迁移到ASP.NET或PHP等现代技术栈
  • 长期:考虑使用云验证码服务(如Google reCAPTCHA)替代自研方案

通过本文的详细讲解和实战案例,您应该能够根据实际需求选择合适的VBScript验证码生成方案,并掌握相关的安全防护和性能优化技巧。在实际部署时,请务必根据具体环境调整代码,并进行充分的安全测试。