验证码的由来 几
年前,大部分网站、论坛之类的是没有验证码的,因为对于一般用户来说验证码只 是增加了用户的操作,降低了用户的体验。但是后来各种灌水机器人、投票机器
人、 恶意注册机器人层出不穷,大大增加了网站的负担同时也给网站数据库带来了大量的 垃圾数据。为了防止各种机器人程序的破坏,于是程序员想出了只有人眼能
够识别的, 程序不容易识别的验证码! 验
证码是一个图片,将字母、数字甚至汉字作为图片的内容,这样一张图片中的内容 用人眼很容易识别,而程序将无法识别。在进行数据库操作之前(比如登录验证、
投票、发帖、回复、注册等等)程序首先验证客户端提交的验证码是否与图片中的内容 相同,如果相同则进行数据库操作,不同则提示验证码错误,不进行数据库操
作。这 样各种机器人程序就被拒之门外了! 但
是随着计算机科学的发展,模式识别等技术越来越成熟,于是编写机器人程序的家伙 可以通过程序将直接写在图片中的内容识别出来,然后提交到服务器,这样验证
码将形 同虚设。为了防止机器人程序的识别,验证码的图片生成也不断在发展,加入干扰点、 干扰线,文字变形、变换角度位置,颜色不同……各种防止计算机识别
的技术也应用到 验证码中。就在这两种技术的竞争中,于是便形成了我们现在看到的验证码,已经有很 多人在抱怨“这是什么验证码哦,人眼都分辨不清楚是什
么”,一切也是无奈。 验证码的使用 验证码是针对各种机器人程序的,所以验证码图片中的内容是不能存放在Cookie、HTML 和URL中的,如果看到一个验证码图片的URL是http://xxxxxx.com/Expwd.aspx?code=1af8
而
验证码图片中的内容就是1af8那将是十分可笑的事情。同时,如果通过抓包发现了 Cookie中保存了验证码的值或者查看HTML时看到了形
如:<input type="hidden"
id="exPwd" name="exPwd"
value="1af8"/>这样将验证码的内容放在隐藏元素中也 是不可思议的。对于这些行为,显然是这个程序员不知道验证码是拿来干什么的,只是 别人的网站上有验证码,与自己的网站也弄一个来赶时髦。另外还有一种好笑的是验证 码看上去像是验证码,结果看HTML代码居然不是一个图片,而是一
个<span>1</span> <span>a</span><span>f<
/span><span>8</span>。大家不要不以为然,以上这几 种情况还真是我现实生活中遇到过的,当年写投票机
器人的时候遇到这种情况我最高兴了 验证码的内容必须保存在服务器端,一般我们可以将随机生成的验证码的内容放入Session 中,用户提交的时候将提交的内容与Session中的验证码进行比较判断。在生成验证码的页 面后台代码可以写为: protected void Page_Load(object sender, EventArgs e) { string checkCode = CreateCode(4); Session["CheckCode"] = checkCode; CreateImage(checkCode); } 比如在登录进行验证的时候可以写为: protected void btnLogin_Click(object sender, ImageClickEventArgs e) { if (Session["CheckCode"] == null) { UIHelper.Alert(Page, "验证码已过期,请重新输入"); return; } if (Session["CheckCode"].ToString().ToLower() != txbCode.Text.ToLower())
//验证码忽略大小写 { UIHelper.Alert(Page, "验证码错误"); return; } //数据库验证…… }
使用C#登录带验证码的网站
前面我们已经对整个验证码的原理和使用有了基本的了解,现在言归正传, 讲讲如何登录带验证码的网站。这里我们以CSDN的登录为例。 1.在IE中正常登录一次并把登录时候的数据包抓下来。 2.分析其中的登录原理如下: 1)请求http://passport.csdn.net/UserLogin.aspx页面,与服务器建立会话, 服务器返回一个SessionID在HTTP的Header中,如下,其他内容我们可以忽略。 ASP.NET_SessionId=ydebagnqgiiixi2dvihfw355; path=/;
HttpOnly,ABCDEF=;
domain=csdn.net; expires=Tue, 22-Apr-2008 17:57:01
GMT; path=/,QWERTOP=;
domain=csdn.net; expires=Tue, 22-Apr-2008 17:57:01
GMT; path=/,activeUserName =Guest; domain=csdn.net; expires=Tue,
22-Apr-2008 17:57:01 GMT; path=/,UserName =Guest; domain=csdn.net;
expires=Tue, 22-Apr-2008 17:57:01 GMT; path=/,PName=; domain=csdn.net;
expires=Tue, 22-Apr-2008 17:57:01 GMT; path=/,ClientKey=;
expires=Tue,
22-Apr-2008 17:57:01 GMT; path=/,userid=0; expires=Tue,
22-Apr-2008
17:57:01 GMT; path=/,ClientKey=933ffb09-5096-4fbb-b90f-5f0bff335b41; path=/ 2)
该页面返回的HTML中有一个<input type="hidden" name="ClientKey"
value= "a50b14fa-2a75-4364-bbeb-3b498b72aa46"
/>这个值在登录提交时也需要,所以需要 从HTML代码中分离出来。 3)将该SessionID作为Cookie的内容发送到验证码生成的页面 http://passport.csdn.net/ShowExPwd.aspx 该页面将返回一个图片的二进制流。 4)将返回的二进制流转换为图片并呈现给用户。 Image img = new Bitmap( Http.GetStreamByBytes("http://passport.csdn.net" ,
"http://passport.csdn.net/ShowExPwd.aspx", b, aspcookie, out header));//获得验证码图片 this.pictureBox1.Image = img; 5)用户输入用户名、密码和验证码,然后和同前面分离出的ClientKey按如下的格式POST 到http://passport.csdn.net/UserLogin.aspx进行验证。 __EVENTTARGET=&__EVENTARGUMENT=&__VIEWSTATE=%2FwEPDwULLTE4NDgzM DI2NjcPFgIeCkZpbmlzaFN0YXloFgJmD2QWB AIBDxYCHgRUZXh0BQznlKjmiLfnmbvlvZVkAgIPZBYCAgMPZBYCAgEPFgIeB1Zpc2libG VoZBgBBR5fX0NvbnRyb2xzUmVxdWlyZVBvc3RCYWNrS2V5X18WAgUeY3RsMDAkQ1B IX0NvbnRlbnQkY2JfU2F2ZVN0YXRlBR1jdGwwMCRDUEhfQ29udGVudCRJbWFnZV9Mb 2dpbr5SL%2FGtMqVCJ%2FCh4jH%2FXp4DhlVU&ctl00%24CPH_Content%24tb _LoginNameOrLoginEmail=studyzy&ctl00%24CPH_Content%24tb_Password=123& ctl00%24CPH_Content%24tb_ExPwd=wgssj&ClientKey=a50b14fa-2a75-4364-bbeb-3b498b72aa46&ctl00%24CPH_Content%24cb_SaveState=on&from=http%3A%2F%2Fhi.csdn.net% 2Fmy.html&MailParameters=&MailParameters=&ctl00%24CPH_Content%24 Image_Login.x=26&ctl00%24CPH_Content%24Image_Login.y=11 6)验证成功的话将返回包含用户信息(发帖数、积分、博客排名等等)的HTML, 验证失败将返回具体的错误信息。 3.以上将CSDN的登录原理分析清楚了,那么接下来就是代码实现了,代码实现比较简单, 我直接在上篇文章所使用的Demo代码上修改的,所以写的不是很漂亮,大家若有兴趣可以 看看。/Files/studyzy/LoginCSDNDemo.rar 成功登录后如图: 现在当前用户已经成功登录了,那么接下来是要在CSDN上发表博客、论坛发帖只需要将当前 的SessionID放入Cookie中,在提交时使用该Cookie即可。
|