zoukankan      html  css  js  c++  java
  • 网页验证码实现步骤及细节

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

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

    效果图:

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

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

    验证码图片生成程序
    <%@ WebHandler Language="VB" Class="verify_code" %>

    Imports System
    Imports System.Drawing
    Imports System.Drawing.Drawing2D
    Imports System.Drawing.Imaging
    Imports System.Drawing.Text
    Imports System.Web
    Imports System.Web.SessionState
    Imports System.Web.Configuration


    Public 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 Property

    End 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.Drawing
    Imports System.Drawing.Text


    Partial 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 Sub
    End 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

    作者:vvian

    出处:http://www.cnblogs.com/vvian/

    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,非常感谢。

  • 相关阅读:
    创建用户自定义函数 SQL
    关于“该列没有包含在聚合函数或 GROUP BY 子句中”
    转Oracle性能参数—经典常用
    The server committed a protocol violation. Section=ResponseHeader Detail=CR must be followed by LF 错误
    js定时刷新
    用户获取mac地址的方法
    聚集索引和非聚集索引的区别
    WCF启动报错:“进程不具有此命名空间的访问权限”的解决方法
    利用js文件加载js文件的方法
    C#下载的几种方法
  • 原文地址:https://www.cnblogs.com/vvian/p/1916792.html
Copyright © 2011-2022 走看看