验证码是最常见的一个功能,在登录页设置验证码输入,可以有效防止暴力破解。
虽然是常见的功能,但是,真正的去看原理,或者手动写一个验证码功能的人并不多,毕竟现在copy 太方便了。
最近客户在使用的系统,突然登录出问题了:明明输入的是正确的验证码,但是,还是提示点击登录的时候,还是提示验证码错误?不是一直都有这个错误提示,可能多次输入,才会偶尔遇到。
如果出现了一次,继续输入正确验证码,还会继续提示验证码错误。
一开始,我怀疑是 nginx转发的问题。但是,后来分析了一下,验证码的校验,都是在后端,和转发没有什么关系。然后,我就看了验证码的实现代码:
原来验证码,是存在cache里。 同样验证码校验的时候,也是从cache里面取出来。用输入验证码作为key去cache中取值。如果有值,则判断,验证码为正确,否则,判断验证码 错误。
代码如下:
var rGraphicCode = System.Web.HttpRuntime.Cache.Get(GraphicCode);
到这里,其实错误已经很明显了。我可以用同一个验证码,多次使用。只要cache,一直还在有效。
而且,用cache存储。和客户端无关。其他客户端,也可以碰撞,随机可能,输入你的验证码。至于为何,我明明输入的是正确的验证码,但是,还是提示错误。这可能是服务器缓存优化,cache被回收了。所以,每次都是提示错误。
那如何解决问题?
请使用session,
Session:在计算机中,尤其是在网络应用中,称为“会话控制”。Session对象存储特定用户会话所需的属性及配置信息。这样,当用户在应用程序的Web页之间跳转时,存储在Session对象中的变量将不会丢失,而是在整个用户会话中一直存在下去。当用户请求来自应用程序的 Web页时,如果该用户还没有会话,则Web服务器将自动创建一个 Session对象。当会话过期或被放弃后,服务器将终止该会话。Session 对象最常见的一个用法就是存储用户的首选项。例如,如果用户指明不喜欢查看图形,就可以将该信息存储在Session对象中。有关使用Session 对象的详细信息,请参阅“ASP应用程序”部分的“管理会话”。注意会话状态仅在支持cookie的浏览器中保留。
session和会话状态相关。所以,使用session才是正确选择。而且,不想和上面代码一样,用生成的随机码作为key。应该固定一个key,然后,每次生成 随机验证码的时候,给session[key]赋值。
这样才是正确的验证码功能。
var rGraphicCode= HttpContext.Current.Session[ValidateKey].ToString();