给ASP.Net表单增加验证码
一、验证码
对于一个预防攻击的web表单来讲,验证码通常是一个常见的措施。因为如果对于一些public区域的页面内容来讲,譬如一个登录表单,如果没有必要的安全措施,很可能遭到模拟登录的暴力破解攻击,要么轻易获得特定账户的登录信息,要么给服务器增加了大量的负荷,影响正常的服务。解决的办法,一般就是在登录前给出一个随机的信息(验证码),显示在页面上,让用户填写,以确保用户是通过web页面来进行正常的登入,对于非法的非web途径登录者会看不到这个验证码从而拒绝其登录。虽然这样,往往很多攻击者会截获登录web页,从而也搜索出验证码,这样,验证保护措施也失去意义,一般情况下,我们可以通过将验证信息作为图像信息显示在web上,这样就既可以不阻碍合法用户登录,又使非法攻击者无法通过html搜索获得验证信息。这大抵上就是验证码的用途和意义了。
二、ASP.Net的验证码实现
一般传统的验证码图像一般采用一些CGI、ISAPI程序加上一些加密代码来动态生成图像,ASP大多采用COM组件实现,相当辛苦。
ASP.Net中欲实现动态验证码却相当容易,笔者大致的思路:
1、 了安全起见,一般存在于CGI程序的url中的验证码加密串最好不要出现在html表单中,而是采用session变量存储,这样验证码的校验会很容易。
2、 采用一个单独的aspx页面专门产生动态程序,要显示的图形验证码信息存在于session中,而一个系统中有可能存在多个表单,为满足整个系统要求可以在aspx后加一个确定的session key的名称,例如
<img src=”http://xxxx/Genimg/viewImg.aspx?sessionKeyName=abc”> 此处的abc就是登录页在第一次输出表单给客户端自动生成一个随机字符串存储在session中的key名称,在服务器端脚本中可以通过session(“abc”)获得生成的字符串(验证码)到底是多少,通过和用户在表单的验证码输入框中输入的内容比较来确定用户是否通过正常的ie浏览器来访问表单。
3、 在表单的第一次显示(get方法)时,生成一个随机数字符串,存入session(“abc”)中,同时将abc作为sessionKeyName的值加入到验证码图形显示生成程序viewImg.aspx的url串中。
4、 ViewImg.aspx分析sessionKeyName,获取session(“abc”)的具体值,利用GDI+产生内存图像,然后修改http header,按照content-type=images/png的格式输出二进制流,这样客户的浏览器会显示出一幅图像,图像表达的内容就是验证码。
5、 当用户填入验证码后,提交到表单验证程序,首先考察其中的验证码输入字段,发现不匹配session(“abc”)马上拒绝,甚至可以累计失败登录次数,乃至拒绝此IP连接,保护系统;匹配session中的存储值,可以进行进一步的其他处理(譬如登录处理,文章发表等),当然也注意销毁此session变量(如果以后不需要)。
6、 不同的表单,可以分配不同的session变量名,这样一个ViewImg.aspx可以为系统多个表单服务。
三、实例解说
重点列出viewImg.aspx吧,具体看清单:
Imports System.IO
Public Class viewImg
Inherits System.Web.UI.Page
Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Dim img As Bitmap
Dim gdiobj As Graphics
Dim ms As MemoryStream ''''--内存流,存放动态图形内存印象
Dim vfycode As String ''''--验证码
Dim SessionKeyname As String
If (Request("SessionKeyName") <> "") Then
SessionKeyname = Request("SessionKeyName")
If (Session(SessionKeyname) <> "") Then
vfycode = Session(SessionKeyname)
Else
vfycode = ""
End If
img = New Bitmap(32, 16) ''''--这个宽高可以根据需要确定
gdiobj = Graphics.FromImage(img)
gdiobj.DrawString(vfycode, (New Font("Arial", 9)), (New SolidBrush(Color.Black)), 0, 0)
ms = New MemoryStream()
img.Save(ms, System.Drawing.Imaging.ImageFormat.Png) ''''--选择透明格式
Response.ClearContent() ''''--原本是准备输出html流,现在输出图信数据,所以要修改http头
Response.ContentType = "image/png"
Response.BinaryWrite(ms.ToArray())
Else
End If
Response.End() ''''--这个最好带上
End Sub
End Class