python-55: 验证码的生成机制

我是研究僧i 提交于 2020-04-07 08:47:15

前面的尝试失败了,为什么呢?

大家可以看到,我们使用了两次urlopen,第一次是打开登陆界面的网址获取验证码的地址,第二次是post数据到指定的网址,我们虽然获取到了验证码,但是这其实是一个很虚的事情,为什么这么说呢?

还是先看前面说的两个网址,

  1. http://id.ifeng.com/allsite/login 这是登陆界面的网址,用来显示输入界面和接受登陆结果的信息

  2. https://id.ifeng.com/api/sitelogin 这是post数据的网址,js脚本,用来向服务器发送数据

我们从登陆界面获取验证码图片,然后向post数据的网址发送data,那么,我们怎么能确定这个过程中验证码有没有改变呢?我们的程序只进行了获取验证码,输入验证吗,post的操作,但是实际上,这中间具体经过了什么样的一个过程我们并不知道,有可能我们第二次使用urlopen来post数据的时候,这个验证码已经改变了呢?如果真的是这样,那我们的代码获取的永远不是最新的验证码,这怎么可能登陆得上呢?

那么,应该怎么知道获取的验证码是不是最新的,或者,有没有什么方法能够保证post数据里面的验证码跟我们网页获取到的是同一个验证码,但同时,我还发现了一个问题

https://id.ifeng.com/public/authcode 这个是我们前面使用RE抽取出来的验证码的图片,我觉得这个网址跟我想象中的不一样,验证码不是每次刷新都不一样的吗?为什么这里就是是一个网址,甚至连什么序号之类的都没有?这不科学

为了找出原因我又重新运行了几次代码,发现还是这个网址,但是点击进去之后图片已经变化了,我又把这个网址输入到浏览器的地址栏,不断的刷新,结果随着我不断的刷新,验证码的图片不断的改变,我很好奇为什么会是这种情况,于是我请教了一些做网页设计的朋友

验证码是什么前面实现那已经说了,那么现在来说说验证码是怎么生成的

我们就拿类似于凤凰网的验证码来说吧,在用户点击登陆界面的时候,程序会自动生成一个随机数,并同时将这个随机数保存到session或者cookies中,生成一个id,以key-values的形式存放,然后通过一定的方法将这些数字或者字母进行处理,比如,扭曲,位置变换等等,最后生成一张图片并显示出来,用户输入后按key来寻找并对比用户输入的数值和随机数生成的数值是否相同

验证码机制是怎么实现

目前主流的实现技术主要有session和cookie两种方式,而这两种方式可以说技术是一样的,区别在于将验证码字符串存储在服务器还是客户端。
前者工作流程:服务器发送验证码图片到客户端并在服务器保存验证码字符串到session,用户辨认图片并提交验证码字符串到服务器,服务器将用户提交的验证码字符串与session中保存的字符串进行比较。
后者工作流程:服务器发送验证码图片以及验证码字符串(可能会进行加密)到客户端,客户端将验证码字符串存储到本地cookie,用户辨认图片并提交验证码字符串以及cookie中所存储的字符串到服务器,服务器将用户提交的两个字符串(进行解密后)进行比较。
相对而言,存放在服务器的session更为安全,只不过消耗服务器内存,程序员除了使用模式识别辨认出验证码,没有其他办法。而对于使用cookie方式的验证码,不增加服务器内存消耗,但我们可以通过对传输数据进行分析轻易破解验证码。

关于cookies和session的更加详细的信息可以到这个网站学习:http://blog.csdn.net/fangaoxin/article/details/6952954

一般来说,为了安全起见,注册、登陆等这些的验证码都是存放在服务器上的,也就是说,大部分是使用session的形式来实现的,如果能找到session-id或者是key,就有办法得到验证码的数据,但是session不是存放在服务器中吗?我们怎么能获取得到呢?

实际上,session是后端的数据,我们并不知道网站设计者在编写代码的时候是怎么设计的,或者做了什么限制,总之我们很难获取得到,通过程序不能获取,甚至浏览器也不能获取,那应该怎么办呢?

cookies,我们知道,浏览器向服务器发送请求,服务器响应并返回数据,当然,这些数据中也包含cookies,用户输入用户名和密码然后登陆网站,如果登陆成功,服务器会将一些信息写入cookies用于下次打开网页的时候自动登陆,如果登陆不上,也会将相应的信息写入cookies,在下次发送请求打开网页的时候告诉服务器,这个用户还没有登陆,需要登陆,从这个角度上来说,cookies代表了你的状态,已经登陆,或者,未登录

我们来设想这样一种情况,当我们打开登陆界面的时候,会随机生成一个验证码(比如:1234),并将这个验证码的信息生成一个session,比如, {key = session-1, values = 1234},这个session的信息是存放在服务器上面的,它需要保密所以不希望浏览器获取到它,那就不给浏览器这些数据,好,现在服务器将不包含有任何session信息的数据返回给浏览器,浏览器提交验证码上的数字来进行登陆,乍一看这整个过程好像没有什么错误,但是,如果100个人同时进行登陆呢?

100个登陆请求就会生成100个session,如果按照前面的方式,100个浏览器同时提交验证码,那么服务器怎么知道哪个浏览器对应的是哪个session呢?

所以,最好的办法是在浏览器发出登陆请求的时候,服务器为浏览器生成一个标识,比如,"这是浏览器a,它对应的是session-1",当然,这个标识是经过加密的,服务器将这个标识和验证码等数据返回给浏览器,浏览器提交验证码的时候要带上这个标识信息,说,"我是浏览器a,对应的是session-1,我提交的验证码数据是1234",然后服务器将这些信息进行比对,如果匹配就登陆成功

这也就是cookies的原理,说了这么多,实际上就是想说明,既然cookies能够携带用户是否已经登陆的信息,那么,它应该也可以携带验证码的信息,虽然不会直接告诉我们验证码是什么,但是会告诉服务器,"我是浏览器a,我刚刚已经请求了一个验证码,对应的是session-1" 类似这样的信息

这也就是我们前面的代码为什么不能成功的原因,我们没有告诉服务器我们发送的验证码对应的是哪个session,这就意味着,我们需要先获取cookies,这个cookies里面包含验证码的信息,然后我们带着这个cookies去post数据


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