大佬总结的很好!我在挖SRC的时候几乎都用过!!
细说验证码安全 —— 测试思路大梳理
1 前言
在安全领域,验证码主要分为两大类:操作验证码 和 身份验证码
虽然都是验证码,但是这两者所承担的职责却完全不同。
操作验证码,比如登录验证码,主要用来 区分人与机器 ,在某种程度上属于图灵测试
身份验证码,主要用来判断账号归属人,解决信任问题,所以更恰当的叫法是 认证码
由于两者的分工和定位不同,所衍生出的安全问题、所关注的安全点也有所不同。
本文将乌云中所有验证码相关案例提炼、分析并汇总,得出一些可重用的方法和经验。
希望本文能给读者带来一些微小的帮助,当你遇到验证码相关业务时,能有一个比较完整的测试和审计思路。
PS:在这一过程中,我居然发现,乌云中的验证码的主要案例类型,与我平时所遇到的案例类型,基本是大致相同的(8大类和5大类)
原来各地的程序员犯的错都是类似的呀 :)
2 操作验证码安全
操作验证码,主要是为了解决三个问题:
1、账户暴力破解
2、高频次的接口访问
3、敏感操作二次确认(CSRF)
实际上这三个问题,都属于 人机区分问题,即 这个操作、请求到底是不是人为地、自愿地发出的?
验证码安全,围绕下面几点展开:
1、验证码可重用 (特定账户暴力破解、CSRF)
2、验证码可识别 (特定账户暴力破解)
3、验证码在客户端生成、显示、校验 (特定账户暴力破解、CSRF)
4、空验证码绕过 (特定账户暴力破解、CSRF)
5、验证码数量有限 (特定账户暴力破解)
6、是否校验客户端可控 (特定账户暴力破解、CSRF)
7、验证码可预测 (特定账户暴力破解)
8、错误超过一定次数才开启验证码 (撞库)
我将乌云上所有的验证码案例汇总分析,共有63个相关案例,得到如下统计结果:
0x01 验证码可重用
这是验证码安全里最常见的一类安全问题,也是最容易遗漏的一类
一般来说,验证码是与Session绑定的,Session生成时,往往也伴随着验证码的生成和绑定。
在访问页面时,接口的请求和验证码的生成通常是异步进行的,这使得两个功能变得相对独立。也就意味着我们如果仅请求接口,而不触发验证码的生成,那么验证码就不会变化。
并且在考虑安全时,开发人员的关注点往往在 验证码校验 是否通过,通过则进入业务流程,不通过则重新填写,而忽视了 这个用户是否按照既定的业务流程在走(接口访问与验证码生成是否同时进行),验证码是否被多次使用了。
理论上来讲,任何验证码只能使用一次或几次,否则就可能导致安全问题
- 案例1 (验证码输入正确时,未销毁重置)
当用户输入正确的验证码时,程序认为其通过了校验,直接进入了业务流程,忽视了验证码销毁重置的问题。
我们可以在输入了正确验证码后,不断重用这一验证码,这导致了 特定账户暴力破解的问题
WooYun这方面的案例有27个
http://www.anquan.us/static/bugs/wooyun-2015-0116594.html 验证正确,未销毁
http://www.anquan.us/static/bugs/wooyun-2016-0169672.html 正确,未销毁
http://www.anquan.us/static/bugs/wooyun-2015-0164315.html 正确,未销毁
http://www.anquan.us/static/bugs/wooyun-2015-0111128.html 正确,未销毁
http://www.anquan.us/static/bugs/wooyun-2015-0110497.html 校验正确后,未销毁
http://www.anquan.us/static/bugs/wooyun-2015-0102697.html 校验正确后,未销毁
http://www.anquan.us/static/bugs/wooyun-2015-099708.html 校验正确后,未销毁
http://www.anquan.us/static/bugs/wooyun-2015-093065.html 校验正确后,未销毁
http://www.anquan.us/static/bugs/wooyun-2014-087890.html 错误,未销毁,可爆破
http://www.anquan.us/static/bugs/wooyun-2014-085942.html 校验正确后,未销毁
http://www.anquan.us/static/bugs/wooyun-2014-084180.html 同上
http://www.anquan.us/static/bugs/wooyun-2014-083092.html 同上
http://www.anquan.us/static/bugs/wooyun-2014-083274.html 同上
http://www.anquan.us/static/bugs/wooyun-2014-082783.html 同上
http://www.anquan.us/static/bugs/wooyun-2014-074661.html
http://www.anquan.us/static/bugs/wooyun-2014-070959.html
http://www.anquan.us/static/bugs/wooyun-2014-056990.html 输入错误时销毁,正确时不销毁
http://www.anquan.us/static/bugs/wooyun-2014-050862.html
http://www.anquan.us/static/bugs/wooyun-2014-049064.html
http://www.anquan.us/static/bugs/wooyun-2013-046547.html 异步机制请求验证码,未销毁
http://www.anquan.us/static/bugs/wooyun-2013-028024.html 同上
http://www.anquan.us/static/bugs/wooyun-2013-025053.html 未销毁
http://www.anquan.us/static/bugs/wooyun-2013-020460.html
http://www.anquan.us/static/bugs/wooyun-2012-013915.html 未销毁
http://www.anquan.us/static/bugs/wooyun-2012-06226.html
http://www.anquan.us/static/bugs/wooyun-2011-03450.html
- 案例2 (验证码输入错误时,未销毁)
当用户输入错误的验证码,而程序没有将验证码重置时,也会存在安全隐患
不过验证码的爆破,有什么意义呢?我们本来就可以看到呀
当一个敏感操作的CSRF存在验证码防御,且验证码比较弱时,我们就可以用js写脚本来爆破,绕过防御
0x02 验证码可识别
- 案例 1(验证码过于简单)
这个属于最简单的验证码,过于简单、清晰、可识别性高,可以编写程序进行识别,导致验证码防御体系失效
WooYun中共有7个类似案例:
http://www.anquan.us/static/bugs/wooyun-2016-0204186.html
http://www.anquan.us/static/bugs/wooyun-2016-0194576.html
http://www.anquan.us/static/bugs/wooyun-2016-0176919.html
http://www.anquan.us/static/bugs/wooyun-2015-0120388.html
http://www.anquan.us/static/bugs/wooyun-2012-012722.html
http://www.anquan.us/static/bugs/wooyun-2012-011765.html
http://www.anquan.us/static/bugs/wooyun-2012-010851.html
实际上,比这个更难识别,更复杂的验证码,也有一些准确率较高的识别方法,我们在测试时把握好效果与成本的平衡即可