网页验证码实现步骤及细节

老子叫甜甜 提交于 2020-01-15 09:42:56

业务部门提出要做一个客户自助查询的系统,而且这个系统是要公布到互联网上的。这样的话,除了一般常见的防注入、服务器安全外,最简单的就是在用户登录处加一个验证码,可以在一定程度上加大恶意尝试破解用户密码的难度。

在网上搜索了一天的类似内容,做成了一个自己的小程序,与大家共同分享,并将使用过程中的小细节说一下,一则备忘,二则也许能让后来的朋友多了解到一点东西吧。

效果图:

老样子,先上代码。个人的习惯,对于做为系统的纯输出功能的代码,使用ashx文件(一般处理程序)而不是aspx文件,呵呵。

先建立一个verify_code.ashx文件,代码如下:

 

 

验证码图片生成程序
<%@ WebHandler Language="VB" Class="verify_code" %>Imports SystemImports System.DrawingImports System.Drawing.Drawing2DImports System.Drawing.ImagingImports System.Drawing.TextImports System.WebImports System.Web.SessionStateImports System.Web.ConfigurationPublic Class verify_code : Implements IHttpHandler, IRequiresSessionState    Public Sub ProcessRequest(ByVal context As HttpContext) Implements IHttpHandler.ProcessRequest                '定义图片大小        Dim bitMapImage As New Bitmap(80, 24)        Dim verity_code As String        '生成图片        DisturbBitmap(bitMapImage)                Dim graphicImage As Graphics = Graphics.FromImage(bitMapImage)        graphicImage.SmoothingMode = SmoothingMode.HighSpeed                '指定字体、大小、风格        Dim fontfamily As New FontFamily("Consolas")        Dim font As New Font(fontfamily, 20, FontStyle.Regular, GraphicsUnit.Pixel)                '生成六位随机字符,使用GetRandomint为生成一个六位随机数字        verity_code = GetRanChar(6)                '将随机字符写到图片中        graphicImage.DrawString(verity_code, font, Brushes.Green, New Point(1, 1))                '在外围画一个边框        graphicImage.DrawRectangle(New Pen(Color.Green, 0), 0, 0, bitMapImage.Width - 1, bitMapImage.Height - 1)        '输出格式为JPG文件        context.Response.ContentType = "image/jpeg"                '将生成的验证码写到Session中,供程序判断        context.Session("verify_code") = verity_code                '输出验证码图片        bitMapImage.Save(context.Response.OutputStream, ImageFormat.Jpeg)        graphicImage.Dispose()        bitMapImage.Dispose()    End Sub        Public Function GetRandomint() As String        Dim random As New Random()        Return (random.[Next](100000, 999999).ToString())    End Function        Public Function GetRanChar(Optional ByVal vinum As Integer = 6) As String        Dim Vchar As String        Dim Vnum As String = ""        If vinum = 0 Then            vinum = 6        End If        '字符串中没有使用0和O,以及小写的L,以免在验证码上看不清楚        Vchar = "2,A,B,C,D,1,E,F,G,H,I,4,J,K,L,M,N,6,P,Q,R,S,T,8,U,W,X,Y,7,Z,a,b,c,d,e,5,f,g,h,i,j,k,m,n,p,3,q,r,s,t,9,u,v,w,x,y,z"        Dim VcArray() As String = Vchar.Split(",")        Dim random As New Random()        Dim i As Integer        Dim iNum As Integer        For i = 1 To vinum            iNum = VcArray.Length            While iNum = VcArray.Length                iNum = Convert.ToInt32((VcArray.Length) * random.NextDouble())            End While            Vnum = Vnum + VcArray(iNum)        Next        Return Vnum    End Function        Private Sub DisturbBitmap(ByVal map As Bitmap)        Dim random As New Random()        '通过随机数生成        Dim k As Integer = 0        While k < 80            Dim j As Integer = 0            While j < 24                '在8%的随机位置产生噪点,100就是无噪点,一般不要小于85                If random.Next(0, 100) <= 92 Then                    map.SetPixel(k, j, Color.AliceBlue)                End If                System.Math.Max(System.Threading.Interlocked.Increment(j), j - 1)            End While            System.Math.Max(System.Threading.Interlocked.Increment(k), k - 1)        End While    End Sub        Public ReadOnly Property IsReusable() As Boolean Implements IHttpHandler.IsReusable        Get            Return False        End Get    End PropertyEnd Class

 

使用以下方式就可以在页面指定的地方显示验证码:

<img id="Verify_code" src="Verify_Code.ashx" width="80" height="24" />

 

代码应该都不复杂,大家可以看明白,如果不明白,复制过去也能使用,就不再多说了,因为这方面的资料也很多,下面就我在编写过程中发现的一些小细节与大家共同讨论一下:

一、验证码的刷新:

如果生成的验证码实在看不清楚,用户就需要刷新一个验证码,很多网站都提供了点击验证码后自动刷新,查看了一下代码,有些是使用了jquery的ajax功能,但我感觉有些复杂,后来用下面这种方法处理了,效果也极好。

 

<img id="Verify_code" src="Verify_Code.ashx?" alt="看不清?点击更换" onclick="this.src=this.src+'?'" width="80" height="24" />

 

二、验证码使用的字体:

如果使用默认的字体,网上的很多识别器都能很快的识别,因为我就想到了用一些不常见的字体来处理这个问题,但在使用中发现了以下的几个情况,大家以后也可用来参考:

1、并不是每一种在字体文件夹中的字体都可以使用,要asp.net能识别出来的才行,否则就只能使用默认字体;

2、新安装的字体有时不能正常使用,网上有资料说是重启一下IIS,但我是直接重启了服务器,有部分字体就被识别出来了;

3、建议使用等宽字体,如果是不等宽字体,万一生成的验证码都是W、M这些宽体字符的话,可能原来指定的图片放不下,影响效果,个人建议使用Consolas字体;

4、使用不同的字体时,字体大小会有很大差别,需要很多次尝试后使用最合适的字体大小,太窄的字体、笔划太细的字体都不适合做为验证码,加上噪点后很看识别出来,也可以使用手写体的数字(最好不要用字母了,不是外国人,真的不好认),不加噪点,也是一种方法。

下面为大家提供一个代码,可以枚举出系统中已安装且可以被asp.net识别的字体,这些字体就可以用在验证码的生成上了:

原文:http://msdn.microsoft.com/zh-cn/library/0yf5t4e8(v=VS.80).aspx

新建一个test.aspx文件,将代码放到test.aspx.vb中直接运行就可以了,前台代码不用修改:

枚举已安装的字体
Imports System.DrawingImports System.Drawing.TextPartial Class test    Inherits System.Web.UI.Page    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load        Dim fontFamily As New FontFamily("Arial")        Dim familyName As String        Dim familyList As String = ""        Dim fontFamilies() As FontFamily        Dim installedFontCollection As New InstalledFontCollection()        fontFamilies = installedFontCollection.Families        Dim count As Integer = fontFamilies.Length        Dim j As Integer        While j < count            familyName = fontFamilies(j).Name            familyList = familyList & familyName            familyList = familyList & ",  "            j += 1        End While        Response.Write(familyList)    End SubEnd Class

大家可以根据自己页面的配色方案,为验证码图片设定不同的背景色、字体颜色、边框色等,我在尝试时发现,颜色那里只接受color数据类型,而不是常见的HTML颜色代码,我也没有再去研究怎么将颜色转换过去了,将就点用吧,但它的颜色都是用单词来设定了,我找到了一个指定颜色的网页,大家可以用来进行一个参考:

颜色代码对照表:http://samples.msdn.microsoft.com/workshop/samples/author/dhtml/colors/ColorTable.htm

测试时发现一个问题,在VS里F5时,没有错,在客户端进行测试时,会因为浏览器缓存的原因导致显示的图片与实际的不符,但这种情况不多且一般客户不会像测试时一样大量的刷新,我就没有再处理,有需要可以自己加上不缓存的代码。

这个验证码系统使用的是用Session来存储验证码的,因此就会有一个情况,如用户打开了二个及以上的窗口时,可能提交到后台时,后台就只会判断最后一次生成的验证码了,如果你的系统要求避免这种情况的话,可以先将生成的验证码进行加密,把加密字符串赋值给一个hidden控件,不过这样的话可能使用jquery控件来处理就更方便了,有空我也试一下,呵呵。

能想到的基本就是这么多吧,大家可以对代码自己进行修改,加上斜体、黑体、删除线、下划线等随机效果,加强验证码的强度。

没有使用更复杂的效果,是考虑到验证码只是一种手段,我们需要其他更多的后台手段来实现系统的安全,如果把精力都放在了验证码上,生怕被识别系统识别出来,一个验证码做的要用户刷新七八次才看认出一部分的话,那就应该本末倒置了,不是提供系统安全,而是折腾人了,这样的话,如果不是非的必要,是没有人愿意再来访问你的网站了。

主要参考资料:

http://www.cnblogs.com/thcjp/archive/2006/07/06/444342.html

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!