# 验证码 验证码是在用户注册、登录等页面,为了防止暴力请求,所加入的一种防范措施。 每次都需要进行验证,而我我们希望只有真人在操作的时候才能通过验证。 使用验证码也是一种有效的防止crsf的方法。 ## 常见验证码技术 本文介绍常见的验证码技术,我们在做爬虫的时候经常需要跟这些验证码技术打交道的。 ### 传统输入式验证码 - 主要是通过用户输入图片中的字母、数字、汉字等进行验证。 - 原理: - 向服务端请求,生成随机的字符,写入会话请求, - 同时将随机字符生成对应图片,响应给前端; - 前端输入对应字符的验证码,向后台发起校验。 - 特点: - 简单易操作 - 人机交互性较好 - 安全系数低,容易被破解 - 采用OCR技术可轻松破解。 ![验证码](./imgs/yzm01.png) ### 短信验证码 - 通过输入有效手机号,获取短信验证码来验证用户的有效性,配合验证码的时效性,大大提高用户的真实性。 - 移动APP较多的采用此方式 - 特点: - 简单便捷 - 有效识别真实手机号 - 会产生显性的短信成本。 - 需要使用第三方支持,常见的产品比如阿里大鱼 ![验证码](./imgs/yzm02.jpeg) ### 输入式的图形验证码 - 有精美的图形,文本内容清晰可见,专注于广告展现。 - 代表:Solve Media - 原理:实现方式同上,只不过是融入了广告元素在其中,无形中创收 - 特点:与其说是验证码,倒不如说是广告位。 ![验证码](./imgs/yzm03.png) ### 纯行为验证码 - 按照要求将备选碎片直线滑动到正确的位置,或拖动滑块移动来达到验证目的。 - 代表:极验验证码 - 特点: - 操作简单,体验好 - 单一维度,容易被逆向模拟 - 与移动端页面切换不兼容。 ![验证码](./imgs/yzm04.png) ![验证码](./imgs/yzm05.png) ### 图标选择与行为辅助 - 给出一组图片,按要求点击其中一张或者多张。借用万物识别的难度阻挡机器。 - 代表:Google新型验证码、12306验证码 - 特点:安全性强。对于图片、图库、技术要求高。 ![验证码](./imgs/yzm07.jpeg) ### 语音验证码 - 通过输入有效手机号,配合图形验证码,获取语音验证码 - 有两种方式: - 在电脑上通过TTS语音播放给用户听到的一种方式 - 现在比较少有的通过语音电话直接呼到用户手机,实现电话语音播报的方式。 - 特点:语音验证,简单安全。有时会产生显性的通话成本 ### 点击式的图文验证与行为辅助 - 通过文字提醒用户点击图中相同字的位置进行验证。 - 代表:淘宝新型验证码、点触验证码 - 特点:操作简单,体验良好,单一图片区域较大,破解难度大。 ![验证码](./imgs/yzm08.jpeg) ### 智能验证码 - 通过行为特征、设备指纹、数据风控等技术,正常用户免验证,异常用户强制验证 - 特点:简单便捷,区分人与机器、人与人、设备与设备 ![验证码](./imgs/yzm10.png) ## 验证码自动生成 此类验证码是最容易使用的,但也最容易被破解,大致步骤: 1. 系统内随机生成一个字符串 2. 字符串写入session保存 3. 字符串利用Python的画图技术,生成一张图片,并把字符串`画`在图片上 4. 为了减少辨识度,可以对图片进行噪点加入等 5. 用户页面显示图片,同时要求在输入框输入图片内容 6. 用户发送过输入的图片内容,跟服务器预存的内容进行对比 我们在下面尝试做一个简单的验证码模块: ### 验证码视图 - 新建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中定义请求验证码视图的url from . import viewsUtil urlpatterns = [ url(r'^verifycode/$', viewsUtil.verifycode), ] - 显示验证码 在模板中使用img标签,src指向验证码视图 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), ]