|
ASP世界
漫话验证码缘起,程序原理及其他
作者:佚名 转自:未知
注:本文中很多资源来源于Internet,版权和本文作者无关,仅仅引用。
我见到的第一个验证码:8723,随机的一数字字符串,最原始的验证码,验证作用几乎为零,呵呵。
MS的hotmail申请时候的: ,BMP格式, 随机数字+随机大写英文字母+随机干扰像素+随机位置+???,这个就让你服气了吧……..不愧是MS老大啊.如果你看不清楚上边的字符了,还可以点下边链接,听语音的读取(注:没有随机背景噪声干扰的,只是TTS语音)。这个倒是很体贴用户!
我Copy一段MS在Passport帮助中的话:
验证码实现流程:服务器端随机生成验证码字符串,保存在内存中,并写入图片,发送给浏览器端显示,浏览器端输入验证码图片上字符,然后提交服务器端,提交的字符和服务器端保存的该字符比较是否一致。一致就继续,否则返回提示。
特别说明的是,其实robot制作者也可以去识别验证码的,所以我说第一种直接输出字符的验证效果几乎为零。而图片的字符识别,就是看图片上的干扰强度了。 就实际的效果来说,验证码只是增加攻击者的难度,而不可能完全的防止。 通过上边的分析,特别是流程分析,相信写出代码是很容易的事情。比如目前流行的实现:
目前流行的WEB开发服务器端技术中,很多都有绘图的API函数,生成图片的代码也就很简单了,就不多提了。这里用没有内置绘图函数Asp,讨论根据已知图片格式,写入2进制数据,生成图片,先乱弹点图形图像的东西。
0所在位置组成了一个”1”字。如果在电子技术上,上图就可以看成一个10x10的点阵。同样的,显示屏也可以看作一个个的点组成。我们输出一组01的信号,明暗相间组成一个图像,就是最简单的黑白位图。简单的显示原理就是这样了。 假想有一个人在控制一组10*10的灯,他利用灯的明暗来显示一个“1”字,那么他用什么样的顺序依次开灯呢。将灯分成水平方向和竖直方向,从左下角的第一个开始,先左到右水平方向控制灯,一行完成后,再向上,依次进行,最后到达右上角结束。 在电子技术上,我们把这样的动作成为行扫描和场扫描,对应描述的行频和场频(刷新频率)就是衡量显像管好坏的重要指标(跑题???)。如果我们用程序控制在屏幕的一块区域(图像大小)中按上边的扫描方法,根据这样一串2进制 字符“1111011111110001111111110111111111011111111101111111110111111111011111111101111111110111111100000111”,将0的位置用白色显示,其他的位置则是黑色,那么我们就输出了一个黑底白字的“1”的图像。当然,如果在windows中显示图像,还要遵循图像的格式标准,否则是无法被系统识别的,所以还要加上表示图像格式本身的信息(图像头)。 啰嗦了这么多,我们来看一个具体的生成BMP格式验证码的代码(本代码是根据网上的一个代码简化的,版权归原作者): vNumberData(0) = "1110000111110111101111011110111101001011110100101111010010111101001011110111101111011110111110000111"
vNumberData(1) = "1111011111110001111111110111111111011111111101111111110111111111011111111101111111110111111100000111" vNumberData(2) = "1110000111110111101111011110111111111011111111011111111011111111011111111011111111011110111100000011" vNumberData(3) = "1110000111110111101111011110111111110111111100111111111101111111111011110111101111011110111110000111" vNumberData(4) = "1111101111111110111111110011111110101111110110111111011011111100000011111110111111111011111111000011" vNumberData(5) = "1100000011110111111111011111111101000111110011101111111110111111111011110111101111011110111110000111" vNumberData(6) = "1111000111111011101111011111111101111111110100011111001110111101111011110111101111011110111110000111" vNumberData(7) = "1100000011110111011111011101111111101111111110111111110111111111011111111101111111110111111111011111" vNumberData(8) = "1110000111110111101111011110111101111011111000011111101101111101111011110111101111011110111110000111" vNumberData(9) = "1110001111110111011111011110111101111011110111001111100010111111111011111111101111011101111110001111" vNumberData(10) = "1111011111111101111111101011111110101111111010111111101011111100000111110111011111011101111000100011" vNumberData(11) = "1000000111110111101111011110111101110111110000111111011101111101111011110111101111011110111000000111" vNumberData(12) = "1110000011110111101110111110111011111111101111111110111111111011111111101111101111011101111110001111" vNumberData(13) = "1000001111110111011111011110111101111011110111101111011110111101111011110111101111011101111000001111" vNumberData(14) = "1000000111110111101111011011111101101111110000111111011011111101101111110111111111011110111000000111" vNumberData(15) = "1000000111110111101111011011111101101111110000111111011011111101101111110111111111011111111000111111" vNumberData(16) = "1110000111110111011110111101111011111111101111111110111111111011100011101111011111011101111110001111" vNumberData(17) = "1000100011110111011111011101111101110111110000011111011101111101110111110111011111011101111000100011" vNumberData(18) = "1100000111111101111111110111111111011111111101111111110111111111011111111101111111110111111100000111" vNumberData(19) = "1110000011111110111111111011111111101111111110111111111011111111101111111110111110111011111000011111" vNumberData(20) = "1000100011110111011111011011111101011111110001111111010111111101101111110110111111011101111000100011" vNumberData(21) = "1000111111110111111111011111111101111111110111111111011111111101111111110111111111011110111000000011" vNumberData(22) = "1000100011110010011111001001111100100111110101011111010101111101010111110101011111010101111001010011" vNumberData(23) = "1000100011110011011111001101111101010111110101011111010101111101100111110110011111011001111000110111" vNumberData(24) = "1110001111110111011110111110111011111011101111101110111110111011111011101111101111011101111110001111" vNumberData(25) = "1000000111110111101111011110111101111011110000011111011111111101111111110111111111011111111000111111" vNumberData(26) = "1110001111110111011110111110111011111011101111101110111110111011111011101001101111011001111110001011" vNumberData(27) = "1000001111110111011111011101111101110111110000111111010111111101101111110110111111011101111000110011" vNumberData(28) = "1110000011110111101111011110111101111111111001111111111001111111111011110111101111011110111100000111" vNumberData(29) = "1000000011101101101111110111111111011111111101111111110111111111011111111101111111110111111110001111" vNumberData(30) = "1000100011110111011111011101111101110111110111011111011101111101110111110111011111011101111110001111" vNumberData(31) = "1000100011110111011111011101111101110111111010111111101011111110101111111010111111110111111111011111" vNumberData(32) = "1001010011110101011111010101111101010111110101011111001001111110101111111010111111101011111110101111" vNumberData(33) = "1000100011110111011111101011111110101111111101111111110111111110101111111010111111011101111000100011" vNumberData(34) = "1000100011110111011111011101111110101111111010111111110111111111011111111101111111110111111110001111" vNumberData(35) = "1100000011110111011111111101111111101111111110111111110111111111011111111011111111101110111100000011" ’ 输出图像文件头 Response.BinaryWrite ChrB(66) & ChrB(77) & ChrB(230) & ChrB(4) & 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(40) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(10) & ChrB(0) &_ ChrB(0) & ChrB(0) & ChrB(1) & ChrB(0) ’ 输出图像信息头 Response.BinaryWrite ChrB(24) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(176) & ChrB(4) &_ ChrB(0) & ChrB(0) & ChrB(18) & ChrB(11) & ChrB(0) & ChrB(0) & ChrB(18) & ChrB(11) &_ ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) &_ ChrB(0) & ChrB(0) For i = 9 To 0 Step -1 ’ 历经所有行 For ii = 0 To 3 ’ 历经所有字 For iii = 1 To 10 ’ 历经所有像素 ’ 逐行、逐字、逐像素地输出图像数据 ,仔细分析这里。 Response.BinaryWrite vColorData(Mid(vNumberData(vCode(ii)), i * 10 + iii, 1)) Next Next Next End Sub %> 显示验证码:showcode.htm <script language="javascript"> var D=new Date(); var hh=D.getHours(); var mm=D.getMinutes(); var ss=D.getSeconds(); document.write("<img src=checkcode_t.asp?time=" + hh + ":" + mm + ":" + ss + " width=120 height=20>"); </script> 上边的调用方法是CSDN论坛里的看到的,可以防止缓存,后退也能刷新,很好,所以一并借用了。。 上边代码的分析,还是大家自己完成吧,仅仅是个示范作用,根据我说的原理,再参考BMP图像的格式(Google一下),应该很容易。下边我们讨论一下增强验证图片作用,加入识别干扰的一些常见方法。 5.验证码中识别干扰技术
前边说了,验证码想要不被攻击者破解是不可能的,但是我们可以加入干扰,增加破解的难道。就好像CSDN的验证码,无干扰,很容易破解,而后边的几个,难道都加大了很多。实际中,干扰主要是分2类,一类是颜色,一类是形状位置。我们来看。
都不知道该怎么结束了,本来还想写破解的,还是算了,下次再说。写了上边些,自己都觉得说不清楚了。。。。。。还是强制结束吧。
|