5. 验证码¶
验证码是在用户注册、登录等页面,为了防止暴力请求,所加入的一种防范措施。
每次都需要进行验证,而我我们希望只有真人在操作的时候才能通过验证。
使用验证码也是一种有效的防止crsf的方法。
5.1. 常见验证码技术¶
本文介绍常见的验证码技术,我们在做爬虫的时候经常需要跟这些验证码技术打交道的。
5.1.1. 传统输入式验证码¶
主要是通过用户输入图片中的字母、数字、汉字等进行验证。
原理:
- 向服务端请求,生成随机的字符,写入会话请求,
- 同时将随机字符生成对应图片,响应给前端;
- 前端输入对应字符的验证码,向后台发起校验。
特点:
- 简单易操作
- 人机交互性较好
- 安全系数低,容易被破解
- 采用OCR技术可轻松破解。
5.1.2. 短信验证码¶
通过输入有效手机号,获取短信验证码来验证用户的有效性,配合验证码的时效性,大大提高用户的真实性。
移动APP较多的采用此方式
特点:
- 简单便捷
- 有效识别真实手机号
- 会产生显性的短信成本。
需要使用第三方支持,常见的产品比如阿里大鱼
5.1.3. 输入式的图形验证码¶
有精美的图形,文本内容清晰可见,专注于广告展现。
代表:Solve Media
原理:实现方式同上,只不过是融入了广告元素在其中,无形中创收
特点:与其说是验证码,倒不如说是广告位。
5.1.4. 纯行为验证码¶
按照要求将备选碎片直线滑动到正确的位置,或拖动滑块移动来达到验证目的。
代表:极验验证码
特点:
- 操作简单,体验好
- 单一维度,容易被逆向模拟
- 与移动端页面切换不兼容。
5.1.5. 图标选择与行为辅助¶
给出一组图片,按要求点击其中一张或者多张。借用万物识别的难度阻挡机器。
代表:Google新型验证码、12306验证码
特点:安全性强。对于图片、图库、技术要求高。
5.1.6. 语音验证码¶
- 通过输入有效手机号,配合图形验证码,获取语音验证码
- 有两种方式:
- 在电脑上通过TTS语音播放给用户听到的一种方式
- 现在比较少有的通过语音电话直接呼到用户手机,实现电话语音播报的方式。
- 特点:语音验证,简单安全。有时会产生显性的通话成本
5.1.7. 点击式的图文验证与行为辅助¶
通过文字提醒用户点击图中相同字的位置进行验证。
代表:淘宝新型验证码、点触验证码
特点:操作简单,体验良好,单一图片区域较大,破解难度大。
5.1.8. 智能验证码¶
通过行为特征、设备指纹、数据风控等技术,正常用户免验证,异常用户强制验证
特点:简单便捷,区分人与机器、人与人、设备与设备
5.2. 验证码自动生成¶
此类验证码是最容易使用的,但也最容易被破解,大致步骤:
- 系统内随机生成一个字符串
- 字符串写入session保存
- 字符串利用Python的画图技术,生成一张图片,并把字符串
画
在图片上 - 为了减少辨识度,可以对图片进行噪点加入等
- 用户页面显示图片,同时要求在输入框输入图片内容
- 用户发送过输入的图片内容,跟服务器预存的内容进行对比
我们在下面尝试做一个简单的验证码模块:
5.2.1. 验证码视图¶
新建viewsUtil.py,定义函数verifycode
此段代码用到了PIL中的Image、ImageDraw、ImageFont模块,需要先安装Pillow(3.4.1)包, 详细文档参考 http://pillow.readthedocs.io/en/3.4.x/
- Image表示画布对象
- ImageDraw表示画笔对象
- ImageFont表示字体对象,ubuntu的字体路径为“/usr/share/fonts/truetype/freefont”
# 验证码 def verifycode(request): #引入绘图模块 from PIL import Image, ImageDraw, ImageFont #引入随机函数模块 import random #定义变量,用于画面的背景色、宽、高 bgcolor = (random.randrange(20, 100), random.randrange( 20, 100), 255) width = 100 height = 25 #创建画面对象 im = Image.new('RGB', (width, height), bgcolor) #创建画笔对象 draw = ImageDraw.Draw(im) #调用画笔的point()函数绘制噪点 for i in range(0, 100): xy = (random.randrange(0, width), random.randrange(0, height)) fill = (random.randrange(0, 255), 255, random.randrange(0, 255)) draw.point(xy, fill=fill) #定义验证码的备选值 # str1 = 'ABCD123EFGHIJK456LMNOPQRS789TUVWXYZ0' str1 = '123456789' #随机选取4个值作为验证码 rand_str = '' for i in range(0, 4): rand_str += str1[random.randrange(0, len(str1))] #构造字体对象 font = ImageFont.truetype('FreeMono.ttf', 23) #构造字体颜色 fontcolor = (255, random.randrange(0, 255), random.randrange(0, 255)) #绘制4个字 draw.text((5, 2), rand_str[0], font=font, fill=fontcolor) draw.text((25, 2), rand_str[1], font=font, fill=fontcolor) draw.text((50, 2), rand_str[2], font=font, fill=fontcolor) draw.text((75, 2), rand_str[3], font=font, fill=fontcolor) #释放画笔 del draw #存入session,用于做进一步验证 request.session['verifycode'] = rand_str #内存文件操作 import io buf = io.BytesIO() #将图片保存在内存中,文件类型为png im.save(buf, 'png') #将内存中的图片数据返回给客户端,MIME类型为图片png return HttpResponse(buf.getvalue(), 'image/png')
配置url:
在urls.py中定义请求验证码视图的urlfrom . import viewsUtil urlpatterns = [ url(r'^verifycode/$', viewsUtil.verifycode), ]
显示验证码
在模板中使用img标签,src指向验证码视图
<img id='verifycode' src="/verifycode/" alt="CheckCode"/>
验证
接收请求的信息,与session中的内容对比
from django.http import HttpResponse def verifycodeValid(request): vc = request.POST['vc'] if vc.upper() == request.session['verifycode']: return HttpResponse('ok') else: return HttpResponse('no')
配置验证处理的url
urlpatterns = [ url(r'^verifycodeValid/$', views.verifycodeValid), ]