如果你的网站中允许匿名用户通过POST方式提交表单, 比如用户注册表, 评论表或者留下用户联系方式的表单,你一定要防止机器人或爬虫程序恶意提交大量的垃圾数据到你的数据库中。这种情况不是可能会发生,而是一定会发生。一种解决这种问题的方式就是在表单中加入人机交互验证码(CAPTCHA), 另一种方式就是在表单中加入honeypot隐藏字段,然后在视图中对隐藏字段的值进行验证。两种验证方式的目的都是一样,防止机器人或程序通过伪装成人来提交数据。今天我们就来详细介绍下如何在表单中添加honeypot增加安全性。
Honeypot的工作原理
Honeypot又名蜜罐,其实本质上是种陷阱。我们在表单中故意通过CSS隐藏一些字段, 这些字段一般人是不可见的。然而机器人或程序会以为这些字段也是必需的字段(required), 所以会补全后提交表单,这就中了我们的陷阱。在视图中我们可以通过装饰器对用户提交的表单数据进行判断,来验证表单的合法性。比如honeypot字段本来应该为空的,现在居然有内容了,显然这是机器人或程序提交的数据,我们可以拒绝其请求。
Django中如何实现表单honeypot验证?
Django表单中添加honeypot,一共分两步:
1. 编写模板标签(templatetags),在包含模板的表单中生成honeypot字段。
2. 编写装饰器(decorators.py), 对POST请求发送来的表单数据进行验证。
由于honeypot的功能所有app都可以用到,我们创建了一个叫common的app。整个项目的目录结构如下所示。只有标蓝色的4个文件,是与honeypot相关的。
编写模板标签
我们在common目录下新建templatetags目录(包含一个空的__init__.py),然后在新建common_tags_filters.py, 添加如下代码。
from django import template from django.conf import settings from django.template.defaultfilters import stringfilter register = template.Library() # used to render honeypot field @register.inclusion_tag('common/snippets/honeypot_field.html') def render_honeypot_field(field_name=None): """ Renders honeypot field named field_name (defaults to HONEYPOT_FIELD_NAME). """ if not field_name: field_name = getattr(settings, 'HONEYPOT_FIELD_NAME', 'name1') value = getattr(settings, 'HONEYPOT_VALUE', '') if callable(value): value = value() return {'fieldname': field_name, 'value': value}
我们现在来看下上面这段代码如何工作的。我们创建了一个名为render_honeypot_field的模板标签,用于在模板中生成honeypot字段。honeypot字段名是settings.py里HONEYPOT_FIELD_NAME,如果没有此项设置,默认值为name1。honeypot字段的默认值是HONEYPOT_VALUE, 如果没有此项设置,默认值为空字符串”。然后这个函数将fieldnam本文来源gaodai#ma#com搞@@代~&码网e和value传递给如下模板片段。
# common/snippets/honeypot_field.html
<div class="form-control" style="display: none;"> <label><input type="text" name="{{ fieldname }}" value="{{ value }}" /> </label> </div>
在Django模板的表单中生成honeypot字段只需按如下操作:
{% load common_tags_filters %} {% load static %} <form method="post" action=""> {% csrf_token %} {% render_honeypot_field %} {% form.as_p %} </form>
编写装饰器
在common文件下新建decorators.py, 添加如下代码。我们编写了check_honeypot和honeypot_exempt两个装饰器,前者给需要对honeypot字段进行验证的视图函数使用,后者给不需要对honeypot字段进行验证的视图函数使用。