CAPTCHA 是Completely Automated Public Turing test to tell Computers and Humans Apart的缩写,够长吧!中文意思是:"全自动区分电脑与人类的图灵测试" 简单来说就是用于区分人类和电脑的验证码图片.
感谢伟大的Google提供了其实现和相应的API. 相关文档大家可自行参考:
http://www.google.com/recaptcha
最近公司的一个项目要使用验证码防止恶意脚本批量注册或遍历破解密码. 传统的解决方式很多,比如IP记录,验证码…但最常见的还是验证码功能,但现在验证码也是有很多弱点的,很容易被破解. 敢兴趣的朋友可以参看相关文章(http://www.xklog.org/article/internet/python-verify-code-recognize-discuz.html) 其实最主要想使用Google Captacha的原因是想省力气,懒得写太复杂的算法. 囧~呵呵
Google Captacha有相应的python实现,但是我感觉默认库可定制性太差,所以只部分采用.
开始之前我先来说下Google Captacha的原理.
传统的验证码是网站先随即生成一个字符,然后保存字符串到session或数据库中.然后把这个字符串生成图片,输出到页面上去.
Google Captacha构架如下图:
步骤看上去比较多,其实对网站开发者来说重点是3步.即图上的1、3、4. 下面稍微解释下
第一步是用户从Google服务器上得到一个验证码图片
没错,是用户获取。对开发人员来说就是在页面加一个ajax调用,当用户加载页面的同时,加载一个Google Capatcha图片即可.
第二步是当用户把含验证码信息表单提到后台,也是web应用最常见的步骤.
第三步是网站后台把用户得到的验证码传递给Google Capatcha服务器验证用户输入的是否正确.
这里就是重点所在,Google服务器如何知道当前验证码输入是否和第一步用户请求到的图片一致,就需要一样东西,即一个随机码. 此外要确定是哪一个网站用户申请的图片和哪一个网站验证图片,需要另外一样东西,即私钥/公钥.
上面简单介绍了下原理,对开发人员来说读代码比看文章管用的多.下面直接开始
一、注册网站私/公钥.https://www.google.com/recaptcha/admin/create
Public Key:
6LcmCL8S*****JH2rJ5l9mgj9xIq63wM0Qeliafm
Private Key:
6LcmCL8S******DFxZh7GY-nWdklo9zWJpQ9Y0yY4
二、编写用户页面,公钥是用户向Google服务器请求一个Capatcha图片. 此步骤需要用户公钥
由于国内加载GoogleCapatcha图片比较慢,我用了异步请求.大致代码如下
HTML
1 |
<script api="" href="http://www.google.com/recaptcha/api/js/recaptcha_ajax.js" http:="" js="" recaptcha="" recaptcha_ajax.js="" src="%3Ca%20href=" type="text/javascript" www.google.com="">http://www.google.com/recaptcha/api/js/recaptcha_ajax.js"</a>/><br /><form id="log_form" action="/ureg/login/?next=/" method="POST"> <br /> <fieldset><br /> <legend>用户登录</legend><br /> <div style='display:none'><br /> <input type='hidden' name='csrfmiddlewaretoken' data-cke-saved-name='csrfmiddlewaretoken' value='7b8a37e39d0d0f89f594867db54a8c43' /></div><br /> <div><label>用户名</label><input type="text" name="username" data-cke-saved-name="username" maxlength="64" /><br /><label class="error"></label></div><br /> <div><label>密码</label><input type="password" name="password" data-cke-saved-name="password" maxlength="64" /><br /><label class="error"></label></div><br /> <div id="gcaptcha"></div><br /> <div class="enter"><br /> <input name="create791" data-cke-saved-name="create791" type="submit" class="buttom" value="提交" /><br /> <input name="Submit" data-cke-saved-name="Submit" type="reset" class="buttom" value="重置" /><br /> </div><br /> </fieldset><br /></form> |
Javascript
1 |
$(document).ready(function(){<br /> google_captcha(‘gcaptcha’);<br />});<br /><br />GOOGLE_CAPTCHA_KEY = 6LcmCL8S*****JH2rJ5l9mgj9xIq63wM0Qeliafm //公钥<br /><br /><br />function google_captcha(element){<br /><br /> Recaptcha.create(GOOGLE_CAPTCHA_KEY,element,{<br /> theme: "clean",<br /> callback: Recaptcha.focus_response_field<br /> });<br />}<br /><br /> |
效果如下:
解析这个图片的HTML.其中有2个字段很重要,它们会在用户提交表单后一起提交给后台,后台服务器必须接受并处理该值
- recaptcha_challenge_field //Google Capatcha随即生成的随机码
- recaptcha_response_field //即用户输入的验证码
三、处理用户提交的recaptcha_challenge_field 和 recaptcha_response_field . 此步骤需要使用用户私钥.
Python
1 |
#!/usr/bin/env python<br /># -*- coding: UTF-8 -*-<br />#<br />import urllib,urllib2<br />from django.conf import settings<br /><br />__author__="Fred"<br />__date__ ="$2010-11-26 10:29:35$"<br /><br />GOOGLE_CAPTCHA_API = 'http://www.google.com/recaptcha/api/verify'<br /><br /><br />class RecaptchaResponse(object):<br /> def __init__(self, is_valid, error_code=None):<br /> self.is_valid = is_valid<br /> self.error_code = error_code<br /><br /><br />def check_google_captcha(request):<br /> """验证google captcha<br /> Submits a reCAPTCHA request for verification. Returns RecaptchaResponse<br /> for the request<br /><br /> recaptcha_challenge_field -- The value of recaptcha_challenge_field from the form<br /> private_key -- your reCAPTCHA private key<br /> remoteip -- the user's ip address<br /> """ |
1 |
#重点<br /> recaptcha_challenge_field = request.POST.get('recaptcha_challenge_field',None)<br /> recaptcha_response_field = request.POST.get('recaptcha_response_field',None)<br /><br /> if not (recaptcha_challenge_field and recaptcha_response_field):<br /> return RecaptchaResponse (is_valid = False, error_code = 'incorrect-captcha-sol')<br /> <br /> def encode_if_necessary(s):<br /> if isinstance(s, unicode):<br /> return s.encode('utf-8')<br /> return s<br /> #把必要项提交给Google Capatcha服务器,私钥在此处使用<br /> params = urllib.urlencode ({<br /> 'privatekey': encode_if_necessary(settings.GOOGLE_CAPTCHA_KEY),<br /> 'remoteip' : encode_if_necessary(request.META.get('REMOTE_ADDR')),<br /> 'challenge': encode_if_necessary(recaptcha_challenge_field),<br /> 'response' : encode_if_necessary(recaptcha_response_field),<br /> })<br /><br /> request = urllib2.Request (<br /> url = GOOGLE_CAPTCHA_API,<br /> data = params,<br /> headers = {<br /> "Content-type": "application/x-www-form-urlencoded",<br /> "User-agent": "reCAPTCHA Python"<br /> }<br /> )<br /> <br /> httpresp = urllib2.urlopen (request)<br /><br /> return_values = httpresp.read ().splitlines ();<br /> httpresp.close();<br /><br /> return_code = return_values [0]<br /><br /> if (return_code == "true"):<br /> return RecaptchaResponse (is_valid=True)<br /> else:<br /> return RecaptchaResponse (is_valid=False, error_code = return_values [1])<br /> |
1 |
rsp = check_google_captcha(request)<br /><br />if not rsp.is_valid:<br /><br /> #验证码不通过,网站可以自定义提示用户 |
Over~~
近期评论