Blog信息 |
blog名称: 日志总数:1304 评论数量:2242 留言数量:5 访问次数:7593715 建立时间:2006年5月29日 |

| |
[Django]Easy Captcha的实现 软件技术
lhwork 发表于 2007/1/15 10:53:57 |
前面的blog中我已经开始研究 pycaptcha 的实现机理,就是想实现一个简单的 captcha 的机制。那么在 session 学习中,我们也了解了 session 的机制与 pycaptcha 的机制差不多,但是我感觉很麻烦。
那么如何才简单呢?考查现有的 pycaptcha 实现,它是将客户端的识别信息与生成图片的文本进行对应,即一个id对应一系列的solution(文本串),前端只看到id,然后通过提交将id和看到的图片中的文本一起传到后台,然后后台处理需要根据id得到对应的solution,再比较solution与上传的文本是否一致。如果一致则成功,否则失败。那么需要在后台保存id与solution的关系,这也很麻烦。因此我想如果前端保存的id包含了生成的文本,那么只要在后台比较这个文本与用户输入的文本是否一致就行了。那么这个id需要足够安全才好。同时可以根据这个id生成相应的图片。因此从处理上可以这样:
首先生成模版,在模版中生成一个key,并将这个key保存到一个hidden字段中。然后再生成一个图片的链接,将key作为一个索引。在传到浏览器后,图片由另一个view方法来根据这个key,得到word,然后根据word来生成一个图片返回。然后用户根据图片的文字进行输入并提交,然后在后台相应的校验方法中,根据key得到word,再比较用户输入的是否相同就行了。
那么整个过程清楚了,下一步就是如何让key既包含word的信息,同时又不容易被伪造,因此我采用将word和SECRET_KEY连接在一起然后生成一个md5的摘要信息,然后再将word生成为base64编码,将这个编码与摘要信息合并成一个字段后就生成这个key了。
生成代码如:
d = md5.new(word + settings.SECRET_KEY).hexdigest()w = base64.standard_b64encode(word)return w+d
那么如何根据key进行校验并得到word呢?代码如下:
def get_key(key): try: d = key[-32:] w = key[:len(key)-32] word = base64.standard_b64decode(w) nd = md5.new(word + settings.SECRET_KEY).hexdigest() if nd == d: return word except: pass return False def valid_key(key, word): k = get_word(key) if k: return k == word else: return False
get_key()是根据key进行校验,并得到对应的word值。valid_key()则调用get_key()来校验和得到word,然后再比较word与上传的文本。在get_key()中,因为生成的摘要串是定长的32位,因此后32位是摘要,前面自然是base64编码后的word了。但为了防止有人知道规则进行伪造,因此要对摘要信息进行验证。方法就是将得到的word再使用相同的方法生成摘要信息,然后比较两个摘要信息是否一致。如果一致说明key是正确的。然后返回得到的word,如果不成功则返回False。然后在valid_key()中,再比较word和上传的文本就可以了。
下面是一个template的例子:
{% load utiltags %}<form method="post" action="/test/valid/"><p>校验码:<input type="text" name="word" value=""/>{% pycall utils.validcode.create_key() as key %} <img src="/test/image/{{ key }}/" align="absmiddle"/></p><p><input type="hidden" name="key" value="{{ key }}"/></p><p><input type="submit" value="提交"/></p></form>
这里我装入了 utiltags tag 模块。并且使用了我新开发的 pycall tag。这样生成一个key就很简单了:
{% pycall utils.validcode.create_key() as key %}
可以看到,生成的key保存到了key变量中了。然后在img标签中要使用这个key,在hidden中要使用这个key。
为了根据img的key生成对应的图片,需要一个view来处理,代码为:
def image(request, key): k = valid_key(key) if k: w, img = get_image(k) return HttpResponse(img, 'image/jpg')
这里使用了一个 get_iamge() 方法,根据指定的文本串来生成图片。但在生成前先要通过 valid_key() 来校验和得到word。
校验代码的简单示意为:
def valid(request): word = request.POST['word'] key = request.POST['key'] w = valid_key(key) if w and w == word: return HttpResponse('成功!') else: return HttpResponse('无效!')
先通过valid_key()对key进行校验并得到对应的word,然后与用户上传的word进行比较,然后给出回复。
在致处理如下,一些方法我使用了以前写的一些东西。 |
|
|