`

验证码能实现验证功能吗?

阅读更多

转载自     RAyh4c的黑盒子      http://hi.baidu.com/rayh4c/blog/item/d0446a092fa056cf3ac7637c.html

 

2006年09月21日 星期四 18:49

这篇文章是一些关于用初等数学的方法来使一些验证码无效的简单介绍。切入正题之前先八卦顺带科普一下。其实关于这方面的话题原来不是安全方面的内容,不过是由于验证码挡住了暴力破解的路子,所以我们要把这颗讨厌的石头给踢开。另外,文中提到的一些例子实际上是低估了算法的能力,这是人为造成的漏洞。同时我们可以借这个机会,看看当前在各个大网站里,部分做技术的人到底有什么样的水平,也算是提高一下自己的自信心。最后,关于这类东西,有些部分涉及到测试的问题,比如Model checking和自动化检测等,如果有朋友以后读这方面的研究生,做做这方面的工作也是挺有趣的,至少论文比较容易出。 

 

小知识:本文所讲的“验证码”是指在网络上确定身份、防止暴力破解、DOS攻击的一种技术,解释起来比较麻烦,实际上上网的朋友都遇到过:动网最新论坛输入账户和密码后并不能直接登陆,还需要输入一串数字验证码;网上银行输入账户和密码也不能正确登陆,还需要输入另一串数字,而这些数字就是本文所讲的验证码中的一种!

在此郑重申明的是:作为作者的我不为这些东西负责,我把铁矿石炼成了钢片,你如果安上刀把用它去杀人,那可就是你自己的事情了!
废话到此结束,让我们进入正题!

 

简单应用
先说技术上实现起来很麻烦,但危害相对较小的一个应用。某国内著名门户网站的校友录(出于众所周知的原因,我这里只能用马赛克来代替这个网站的网址,想必大家平时也常去的),访问这个网站的时候,Cache里面就有验证图片,拷出来用就可以了。写文章的时候它已经作了简单的调整,不过没有关系,我们先看以前的,然后看看当前的情况。
在校友录留言的时候,一定要让你输入四个数字的验证码,说法是防止恶意灌水。在留言的页面查看源代码可以看到,图片是从这个地方得到的:
<img src='http://chat.superalumni.xx.xx/gen_img_digital.php?Key=lw9999929999999' width=80 height=20 border=1>
另外还有一个格式为Hidden的表项,里面是Key的值,和上面的Key值一样。到这里我们可以猜测一个什么结果呢?首先为了减轻服务器的负担,它没有为每个连接建立一个用于验证码的Session,而是在发表留言的时候从客户端得到用户的输入以及这个隐藏的项,通过一系列的算法来判定你的提交是否正确。这是很容易理解的,不过给人的感觉似乎不太可靠。


我们继续做实验。将上面的代码复制到一个新建的HTML文档中,直接用浏览器打开。几秒钟后出现在我们面前的是和上次看到的不同的图片,但是数字是一样的,多刷新几次看看,图片变了,但是图片上面的数字还是一样的!这是一个很重要的问题,也就是说Key的值与图片最后显示的数字有着一一对应关系,而图片本身无论怎么变,都不会影响到Key和图片上的数字。直观一些,我们用下面的示意图来说明:


pic(图片)----------> +------------------+
|| | Result(结果)|
Key(种子)---------> +------------------+


种子就是服务器指定的Key的值,在浏览器层面上我们看到的是图片PIC,在服务器上我们提交的验证码要与结果Result相比较。对于某校友录而言,它的工作方式可以看成从Key生成到Result,而用户是从PIC生成到Result。

 

脚本小子:这里其实是相当聪明的做法,由于计算机和算法能力的限制,模式识别和人工智能一直没有很大的突破性的进展,验证码就是有效的利用了计算机不能做到而人能够轻易作到的事情来分辨人与机器,尽管某校友录的技术或者管理人员并不知道个中原理和细节,但是他们还是聪明的用了这一种方法。

 

客观地说,有好多事情其实想法本身是很好的,不过在具体做的时候,却由于技术或者理解上的原因弄得很糟糕。空口无凭,让我们来具体分析一下,看看这个校友录的验证码到底强壮性如何。


首先是Key。Key和Result显然是一一对应的,校友录肯定有某种算法来完成Key到Result的函数映射,然而我们却不关心这种算法,也没有必要去关心,因为Key和Result居然是我们自己提交的。这个问题也可以这样来看,本来应该是服务器提出问题,然后我们回答,然后服务器再判断,而实际的情况却成了我们提出问题和答案,服务器来判断是否正确。这并不是一个正确的Challenge,某校友录的技术人员显然是没有这方面的常识,设想:如果我清楚了一个问题和它的正确答案,提交给你的时候,你除了回答正确还能做些什么呢?如果我每次都提交同样的这个问题和它的正确答案,我想除非服务器除了故障,否则回答都应该是“正确通过了验证码”——但是这种时候验证码还在起作用吗?根本就是一个摆设罢了!
第一种绕过的方法出来了,就是自己伪造经过确认的Key和Result。这里的“经过确认”有很多种方法,最简单的就是用眼睛看,看了后记录下来反复使用就可以了。
你说投机取巧?也许吧,如果有两条路子可以爬上山,你愿意坐索道还是愿意走楼梯?如果回答是后面的那个,OK,I服了U,有自虐倾向的朋友请继续往下看。


就算不用这种绕开的方法,还是可以从Key到Result的。当然不是直接去找寻算法,也不是构造一个足够大的数据库来供查询,而是直接可以从图片到结果——让程序来判定图片到底是什么数字。
这种做法看起来不太可能,因为验证码的一个首要条件就是:人能够很容易的识别,但是计算机却不能。这是一个基本的大前提,如果这个大前提都不成立,那么验证码根本就是一个笑话。但是事实总是很耐人寻味的,就像考研和蹦极一样,有些事情你不亲自去做做你是不会相信有那么简单的——如果你和我一样,也花上一个下午的时间去抓回来四百来个图片的Sample,你就不会再相信这种验证码牢不可破了。


有兴趣的话,你可以自己抓来看看,抛开背景图案上像芝麻一样的黑点(后面管这些叫背景噪音),对于同一个数字,比如2,你有没有看到有三种不同的写法?没有……确实没有,如果不注意观察,很有可能就被某校友录给蒙了。这里没有颜色的区别,没有字体的变形,也没有让人恼火的颜色渐变,就只有光秃秃的两种颜色——黑黑的字和白白的背景,以及不过两种不同大小的四个数字在上面。总共有多少种数字呢?从零到九一共十个数字,有两种字体再乘上二,看上去华丽的验证码不过是从二十个不同的数字中随机的选了四个而已。


不是还有背景噪音么?
确实,这些可爱的背景噪音们部分地挡住了我们的视线。如果是单纯的在一个二维平面上去寻找看是否存在某个图形,这是一个参加过校级程序设计大赛的中学生都能在半个小时内完成的简单题目。现在有了背景噪音,纯粹的匹配算法会不会失效呢?我们仔细地想想,如果这张图片已经充分地处理过并且存放在一个简单的二维数组里面,而且我们清楚地知道那二十个基本数字的形状,纯的匹配办法还是有价值的。一张图片上总是四个数字(后面还有详细说明),把这四个数字所在的部分大体上分离出来成为四个部分,每一部分依次与那二十个基本形状相比较,总会有一个完全能够地重合。这时候我们再引入背景噪音的概念,由于背景噪音总是和字符的颜色是相同的(其实是经验,肉眼没有能够分辨出来),所以待匹配(识别)的图像部分中,加入背景噪音后只可能比之前的黑点要多,这个基本不影响匹配的结果——如果我们用标准的二十个样本图案作为基准,发现在一次比较中,某些位置在样本中是字体而在待匹配(识别)的图像部分中是空白背景,这显然就不和当前比较的图案相同。

 

这是很容易理解的,比如我们拿着照片看人,照片是新照的,不过现实中的人脸上不巧被蚊子咬了一个疙瘩,我们这样比较依然是没有错的,因为我们以相片为基准,相片上有的两个眼睛一个鼻子一个嘴巴都和待辨别的人脸上的器官能够完全吻合,尽管多了一个蚊子疙瘩,我们还是有理由认为他就是照片上的人(多说一句,只满足了必要条件),但如果我看到的人是个三只眼睛的,显然能够判定不是。也就是说,加入噪音以后,匹配的图案只是经验上能肯定,但不匹配的图案是能准确判定的,去伪之后,自然是存真。对于这个的证明,离散数学中第一章有个析取三段论,有空可以翻翻,这里就不写了(脚本小子:记忆尤深的一章,想当初每次考试前都信誓旦旦的要复习,但书总是翻不过这一章。历次考试莫不如此……)。


有人可能还会抬杠,倘若你的数字是9,刚好背景噪音都集中在了左下角,变成一个8怎么办?对于这种情况,我首先应该表示遗憾,如果真的有这种情况发生,我建议你放下手上的杂志跑楼下转角处买体彩去。理论上来说发生这种事情的几率小于十万分之一,一旦发生,肉眼都不能正确识别(谁想得到呢?),我们不应该苛求电脑,毕竟前面说过,加了无法去掉的背景噪音以后,匹配只是满足了必要条件,要想充分满足,除非还有别的条件可以用。
真的有别的条件么,别的条件在什么地方?
有!在GIF文件里面。你也许不熟悉GIF文件,我们可以这样想象,不同的数字是可以对应相同颜色的,这个校友录上的GIF文件还原后的数字集合是怎么样的呢?来看一个例子(仅仅是片断)。


0100000000000000
0000000000000000
0000222222200000
0000220000000000
0000220000000000
0000220222001000
0000000000001000

 

脚本小子:这里简单的解释一下,GIF文件以LZW压缩算法把二维的图像进行压缩,原始图像上的每一个像素对应解压后的GIF数据中的一个数字(索引)。这个数字并不是原始图像的值,而是对应的一种颜色的序号,在还原的时候要通过这个值去查GIF文件头中定义的颜色(调色盘),然后再进行显示。打个比方,比如数字是1,查到的颜色是#CCCCCC#,那么这个地方应该显示灰色——查了好久才找到的东西,累个半死。

背景的索引是0,噪音的索引是1,而数字轮廓的索引是2,它们是分开的。
很难理解某校友录的工程师出于何种考虑进行了这样的GIF编码,这根本就是人为造成的一个缺陷,其结果是我们对GIF文件进行解码以后没有必要进行背景去噪这一个步骤,因此我们的识别程序是完美的(数学中叫条件充要)。


综合上面提到的各步分析,识别这个校友录程序的基本框架是:获取GIF图像,GIF图像解码,去掉解码后为1(背景噪音)的部分,划分成四个基本块,依次与二十个标准样本进行比较,最后获得结果。


到写完文章的时候再看这个校友录,情况已经发生了微小的变化。这个校友录在生成验证图片的时候,已经结合了登陆的Session,所以单纯静态地提交Key与验证码的值已经不能绕过验证。但是生成的图片过于简单的老问题依然存在,用正当的方法获取到验证码之后,用上面的代码还是可以自动识别。有一点需要注意:标准样本这个时候已经发生了一点小小的变化,数字样本有一半需要更新,这个工作是很简单的,三十分钟就可以完成——如果你知道我在讲什么而你又刚好明白它的危害的话!


我们来模拟一下这个校友录验证码的设计思路。我想他们的工程师是这样想的:首先随机生成一个Key,通过这个Key和一个初始化的种子Seed经过一系列的函数变换,生成一个四位数的验证码Result,这个Result再被变换成为中间的图像并随机加上背景噪音,最后再生成GIF图像。Result到GIF图像并不是一个(单值)函数映射,估计在这一步麻痹了这些工程师们,实际上这一步是不重要的,关键在于变换的算法,太简单就没意义了。

脚本嚣张:这里补充一句,由经验看来,Key的值每一次都是增长的,很有可能这个数字与点击率或者访问量相关,如果真是这样,预测性质的攻击也完全有可能——希望我们只是在杞人忧天。

 

OK,简单的说一下危害。这里这个地方危害很小,最多也就灌灌水什么的,或许有些别有用心的人会弄点“怎么利用网络赚大钱”等东西大量地往上面帖,但危害都不怎么大,就象黑防论坛长期都在删这样的帖子一样。
灌灌水你当然不会觉得有什么危害了,如果是电信或者银行也有这个问题你怎么办?


手机的密码都是6位的数字,银行的卡也就是6位的数字密码,如果让你在手机或者ATM上去暴力破解,首先没有这个硬件,其次速度太慢,毕竟一百万个可能性要想猜出来还是有点困难。现在网上有的地方允许你输入手机号码和密码就可以订制服务和发送短信,仅有的一点保护措施也就是很简单的验证码,网上银行也有类似的情况,这时候用电脑来跑密码的话,速度就比较可以接受了,一旦密码跑出来,可就不是灌灌水这样简单的事情。这种状况的安全,还真叫人不放心自己的票子。


某省移动的验证码自动识别程序也是个很搞笑的东西,从技术上来看,这个验证码到了能够做到的最简单的极致,除了不设验证码,没有比这个更为脆弱的保护机制了。结合这个东西,你可以做什么?像以前流行的破解300电话卡的方法一样,固定一个密码,然后穷举卡号(电话号码),假以时间,肯定是可以猜出些东西。这种被破解掉的厄运会不会降临到你我头上呢?神仙姐姐可能才知道。


还有,刚和某杀毒公司吵了一架的银行很安全么?看到这里,我想你自己会有一个判断。如果你感兴趣并且想具体看看那些验证码的话,可以参考一篇叫做《使用 HTTPS 编写客户端程序》的翻译文章,因为单纯用右键另存为无法把那些BMP图片保存下来。不过我建议你即使做出来了识别码的自动识别工具也不要妄图去暴力破解密码,原因不是说你跑不出来(我承认非常容易跑出密码来),而是你玩不过。作为炫耀的资本当然是可以的,在雷区以外,我一向都是很自由地释放自己的活力的,呵呵(脚本小子:这点是作者特别自负的地方,也是俺最深恶痛绝的地方,详细情况天知地知,唉……)。


同样的东西还出现在那些诸如网上卖卡片的网站,用“飞不起来的肥鸟”作标志的即时通讯软件的网站等等的上面,反正大部分都适用于那个简单的比较算法,就算是有点变形,也可以用比较初等的办法识别出来(限于篇幅,这里就不一一介绍了)。如果有时间,可以写一个比较通用的识别程序(外面也有,车牌识别的,不过是商业用途),只要给定一些图片并告诉程序是什么(作为训练集),以后就可以自己识别了,这样子比较方便。


最后谈谈自己的看法。用测试的眼光看,辅助验证无非就是给一个最后的机会,让你确认一下是否要提交请求,同时也给接受者一个保证——这确实是用户亲自提交的。功能上看来,辅助验证并不针对密码保护和防止暴力破解,作为潜在的功能可能也会有些效果,然而在运用中往往这种效果被夸大。对于防止暴力破解,很容易想到的一个保护方法是限定规定时间登陆次数,但这种工作在很多地方被一种畸形的辅助验证码给代替掉,结果导致了漏洞的产生。这种意义上的问题,在模型检测中似乎是不能自动检测出来的,或许,应该有另外技术来检测这种“夸大适用范围”或者叫做“误用”的错误?期待ing!

分享到:
评论

相关推荐

    Java后端产生验证码后台验证功能的实现代码

    Java后端产生验证码后台验证功能的实现代码 Java后端产生验证码后台验证功能的实现代码是指在Java后台生成验证码,并对其进行后台验证的功能。本文主要介绍了Java后台产生验证码后台验证功能的实现代码,结合实例...

    Java实现验证码验证功能

    通过以上步骤,我们可以在Java Web应用中实现一个基本的验证码验证功能。Servlet负责处理HTTP请求,session用于在服务器端存储验证码,而画板对象则帮助我们在图像上绘制随机字符,生成可视化的验证码。这个过程涉及...

    javaweb邮箱发送验证码功能实现

    在JavaWeb开发中,实现邮箱发送验证码功能是常见的需求,主要应用于用户注册、密码找回等场景,以确保安全性和合法性。下面将详细讲解这个过程涉及的技术点和步骤...确保正确配置并理解这些步骤,就能顺利实现该功能。

    SSM实现登录验证码功能

    在这个“SSM实现登录验证码功能”的项目中,我们将探讨如何在SSM框架下添加验证码功能,以增强用户登录的安全性。 首先,验证码功能的基本目的是防止恶意自动化程序(如机器人或爬虫)进行非法操作,如频繁尝试登录...

    使用Vue 实现滑动验证码功能

    本文将详细介绍如何使用Vue框架来实现滑动验证码功能,为读者提供一个实现前端校验验证码的实例。 首先,我们要了解验证码的基本原理。验证码分为前后端校验两个阶段。前端校验主要防止自动化程序(机器人)进行...

    asp.net mvc验证码实现

    在这个场景中,我们关注的是在ASP.NET MVC中实现验证码的功能。验证码的主要目的是防止自动机器人或恶意用户进行非法操作,例如垃圾邮件提交、恶意注册等。下面将详细讨论如何在ASP.NET MVC中实现验证码。 首先,...

    验证码 注册验证 验证码验证

    在AspTest2这个文件中,可能包含了实现上述验证码验证功能的源代码,包括生成验证码、显示验证码、接收和验证用户输入的验证码等相关逻辑。通过分析和学习这些代码,开发者可以理解验证码验证的具体实现细节,以便在...

    易语言验证码拖拽滑动验证源码

    在这个“易语言验证码拖拽滑动验证源码”中,开发者@大司命提供了一种实现验证码拖拽滑动验证的方法。这种验证机制常用于网络安全领域,以增加网站或应用的安全性,防止自动化程序的恶意操作。 验证码通常由随机...

    JSP验证码+js验证

    总结,JSP和JavaScript在验证码实现中分别负责后端图像生成和前端用户输入验证。理解这两部分的工作原理有助于构建更安全、用户体验更好的Web应用。同时,对于防止自动化攻击,还可以考虑结合其他策略,如时间限制、...

    Android验证码的实现

    本篇文章将深入探讨如何在Android平台上实现验证码功能,包括自定义控件的创建和验证码的生成与验证。 首先,验证码的主要目的是防止恶意机器人或自动化脚本进行非法操作,如批量注册、刷票等。在Android应用中,...

    asp.net短信登录验证码和图片验证程序源码

    实现了验证码倒计时的功能 1.以下验证码例子采用的是先获取手机号文字验证码,如果文字验证码收不到,将采用语音播放验证码的形式,两种形式的结合,基本避免个别手机号收不到的问题,从而是验证码的成功率接近100%...

    PHP快速生成图片验证码并且实现验证插件.rar

    PHP快速生成图片验证码并且实现验证插件 1.插件作用: 本插件可以快速实现网站验证码功能,包括验证码的生成和验证。   2.所需参数: CaptchaTool类包括两个方法,generate方法可以实现生成'...

    java实现验证码产生功能

    在Java JSP(Java Server Pages)中实现验证码功能,主要涉及以下几个关键知识点: 1. **随机字符串生成**: 验证码通常由一组随机字符组成,可以是字母、数字或两者混合。在Java中,我们可以使用`java.util....

    Android实现获取短信验证码的功能以及自定义GUI短信验证

    Android实现获取短信验证码的功能以及自定义GUI短信验证,对应文档链接http://blog.csdn.net/u012532559/article/details/51027136;代码为平时测试demo,还附加了自定义等待框以及阿里iconfont的使用

    [PHP编程之道]生成图形并添加验证码实现验证功能

    生成图形并添加验证码实现验证功能 FROM:新浪博客【林雪在奋斗】 1123今天贴一个简单图形生成验证码的代码出来【php编程之路】 如在学习php中遇到问题,可投邮件址:xuelinweb@hotmail.com 或许我们可以一起讨论并...

    用免费短信验证码SDK实现手机注册验证功能.zip_手机注册验证_手机验证_短信注册_短信验证码

    本教程将详细讲解如何利用免费短信验证码SDK来实现这一功能。短信验证码是一种通过发送带有随机数字或字母的短消息到用户手机,然后让用户输入以验证其身份的方法。这种方法既能有效防止恶意注册,又能降低欺诈风险...

    asp.net实现验证码功能

    总之,ASP.NET结合C#和System.Drawing能方便地实现验证码功能,有效地保护了网站免受自动化的恶意攻击。在实际开发中,还可以根据需要添加更多安全特性,比如时间限制、滑动验证码、声音验证码等,进一步提高系统的...

    C#滑动验证码(类似腾讯滑动验证)

    总的来说,这个C#滑动验证码项目涵盖了前后端开发、数据库设计、安全性策略以及用户体验等多个方面,是理解Web应用中验证码实现的一个实例。通过深入研究这个项目,开发者可以了解到如何在实际项目中实施类似的安全...

    简单几步实现滑动验证码(后端验证).doc

    实现滑动验证码(后端验证) 滑动验证码是指用户需要通过滑动图片来证明自己不是机器人的一种验证码方式。LazySlideCaptcha是一个基于.Net Standard 2.1的滑动验证码模块,提供了一个基于Vue 2的演示前端组件和背景...

    JavaWeb练手-实现登录注册(含验证码和表单验证)

    在本项目"JavaWeb练手-实现登录注册(含验证码和表单验证)"中,主要涉及了几个关键的JavaWeb开发技术,包括Servlet、HTML、JSP以及验证码和表单验证的实现。以下是这些知识点的详细说明: 1. **Servlet**:Servlet...

Global site tag (gtag.js) - Google Analytics