Braid信息安全博客 - Web安全|代码审计|安全开发|Java|php|python

【安全加固】 验证码的实现原理和安全问题汇总

0x01 前言

这篇文章将通过一个实例来讲解验证码的原理,并整理下不合理的设计或使用验证码所引发的安全问题。写这篇文章原因是周末看laravel验证码实现那块发现居然忘记验证码的实现原理了,好记性不如烂笔头,所以要多做笔记~

0x02 Captcha原理

我们先来看下验证码实现原理

1.客户端发起一个请求;
2.服务端响应并创建一个新的SessionID同时生成一个随机验证码;
3.服务端将验证码和SessionID一并返回给客户端;
4.客户端提交验证码连同SessionID给服务端;
5.服务端验证验证码同时销毁当前Session中的验证码,返回给客户端结果。

0x03 Captcha实例

github上https://github.com/HackBraid/Sec-ReinForce
里面有个文件夹Capthca,一个标准、安全的验证码流程的demo,有兴趣可以git下来本地搭建下。
我们本地搭建好后可以测试下这个验证码流程。首先在chrome浏览器设置好burp的代理,然后访问:http://localhost:8081/Capthca/
可以看到burp拦截到的请求包如下:

我们点击Forward按钮,发现服务器的返回包中的Set-Cookie字段会设置sessionID为一个较长的字符串:


我们输入验证码,然后拦截请求,请求包头部会带着sessionID:

然后服务器端会取这个sessionID的验证码与用户提交的验证码进行比对,成功验证后销毁,然后再验证用户名、密码等信息。

session.removeAttribute("CHECK_CODE");  
out.print("验证码通过,服务器正在校验用户名和密码!");

通过这个验证码的demo我们可以比较清晰的理解其原理了,当然这里session是通过文件来实现的。

0x04 Capthca的安全问题

验证码的设计之初就是为了限制攻击者的撞库、爬虫等攻击,然而不合理的设计或使用验证码就会引发一些安全问题。借用前人的总结,根据验证码的实现流程,其问题可以分为三类:客户端问题、服务端验证问题和验证码可被识别。

客户端问题

1.客户端生成并验证验证码(验证码由客户端js生成并且仅仅在客户端用js验证)
2.验证码输出客户端(验证码直接输出到html、cookie中)

服务端验证问题

1.验证码重用
验证码没有及时销毁导致可重复使用,即如果通过验证,没有销毁当前session里的验证码。这里可以将上面的demo中session.removeAttribute(“CHECK_CODE”); 这行代码注释掉即可复现验证码重用问题。
2.非空判断
很多时候,我们会遗留掉了验证过程中验证码为空的情况,比如去掉cookie中的某些值或者请求中验证码参数,结果就直接通过了验证码验证。
3.其它
像无论输入什么都通过这种不验证的、多个登录入口其中一处未加验证的和请求的url中去掉一些参数即可绕过登录验证码验证的情况也很多。

验证码可被识别

验证码过于简单可以被识别,验证码识别已经有很多现成的工具可以使用了,这里引入随风师傅的一篇文章:
https://www.iswin.org/2016/10/15/Simple-CAPTCHA-Recognition-with-Machine-Learning/

0x05 Capthca的产品

专门做验证码的公司也不少,下面是国内外公司:
国内做的比较优秀的是:极验
国外是被谷歌收购的公司reCAPTCHA。
大家可以自行了解下~

附:
Session的存储方式
最近在学习Laravel,然后发现除了传统的file型Session存储方式外还有以下几种:

database :将Session数据存放到指定数据表中,该数据表由配置项 table 设置
memcached :将Session数据存放到Memcached中
redis :将Session数据存放到Redis中
array :将Session数据存放到数组中,该配置仅用于测试环境

数据库存储方式主要是为了应对大型网络架构中file存储方式的不足。

参考来源:
http://cb.drops.wiki/wooyun/drops/web-5459.html

本文由HackBraid整理总结,原文链接:http://www.cnbraid.com/categories/安全运维/captcha.html,如需转载请联系作者。