文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

使用Django怎么给表单添加honeypot验证

2023-06-14 23:04

关注

这篇文章给大家介绍使用Django怎么给表单添加honeypot验证,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。

Honeypot的工作原理

Honeypot又名蜜罐,其实本质上是种陷阱。我们在表单中故意通过CSS隐藏一些字段, 这些字段一般人是不可见的。然而机器人或程序会以为这些字段也是必需的字段(required), 所以会补全后提交表单,这就中了我们的陷阱。在视图中我们可以通过装饰器对用户提交的表单数据进行判断,来验证表单的合法性。比如honeypot字段本来应该为空的,现在居然有内容了,显然这是机器人或程序提交的数据,我们可以拒绝其请求。

Django中如何实现表单honeypot验证?

Django表单中添加honeypot,一共分两步:

编写模板标签(templatetags),在包含模板的表单中生成honeypot字段。

 编写装饰器(decorators.py), 对POST请求发送来的表单数据进行验证。

由于honeypot的功能所有app都可以用到,我们创建了一个叫common的app。整个项目的目录结构如下所示。只有标蓝色的4个文件,是与honeypot相关的。

使用Django怎么给表单添加honeypot验证

编写模板标签

我们在common目录下新建templatetags目录(包含一个空的__init__.py),然后在新建common_tags_filters.py, 添加如下代码。

from django import templatefrom django.conf import settingsfrom django.template.defaultfilters import stringfilterregister = 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, 如果没有此项设置,默认值为空字符串''。然后这个函数将fieldname和value传递给如下模板片段。

# common/snippets/honeypot_field.html

<div class="form-control" >        <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字段进行验证的视图函数使用。

#common/decorators.py

from functools import wrapsfrom django.conf import settingsfrom django.http import HttpResponseBadRequest, HttpResponseForbidden, HttpResponseRedirectfrom django.template.loader import render_to_stringfrom django.contrib.auth.decorators import user_passes_testdef honeypot_equals(val):    """        Default verifier used if HONEYPOT_VERIFIER is not specified.        Ensures val == HONEYPOT_VALUE or HONEYPOT_VALUE() if it's a callable.    """    expected = getattr(settings, 'HONEYPOT_VALUE', '')    if callable(expected):        expected = expected()    return val == expecteddef verify_honeypot_value(request, field_name):    """        Verify that request.POST[field_name] is a valid honeypot.        Ensures that the field exists and passes verification according to        HONEYPOT_VERIFIER.    """    verifier = getattr(settings, 'HONEYPOT_VERIFIER', honeypot_equals)    if request.method == 'POST':        field = field_name or settings.HONEYPOT_FIELD_NAME        if field not in request.POST or not verifier(request.POST[field]):            response = render_to_string('common/snippets/honeypot_error.html',                                    {'fieldname': field})            return HttpResponseBadRequest(response)def check_honeypot(func=None, field_name=None):    """        Check request.POST for valid honeypot field.        Takes an optional field_name that defaults to HONEYPOT_FIELD_NAME if        not specified.    """    # hack to reverse arguments if called with str param    if isinstance(func, str):        func, field_name = field_name, func    def wrapper(func):        @wraps(func)        def inner(request, *args, **kwargs):            response = verify_honeypot_value(request, field_name)            if response:                return response            else:                return func(request, *args, **kwargs)        return inner    if func is None:        def decorator(func):            return wrapper(func)        return decorator    return wrapper(func)def honeypot_exempt(func):    """        Mark view as exempt from honeypot validation    """    # borrowing liberally from django's csrf_exempt    @wraps(func)    def wrapper(*args, **kwargs):        return func(*args, **kwargs)    wrapper.honeypot_exempt = True    return wrapper

上面代码最重要的就是verify_honeypot_value函数了。如果用户通过POST方式提交的表单里没有honeypot字段或该字段的值不等于settings.py中的默认值,则验证失败并返回如下错误:

# common/snippets/honeypot_error.html

<!DOCTYPE html><html lang="en">    <body>    <h2>400 Bad POST Request</h2>    <p>We have detected a suspicious request. Your request is aborted.</p>    </body></html>

定义好装饰器后,我们对需要处理POST表单的视图函数加上@check_honeypot就行了,是不是很简单?

from common.decorators import check_honeypot@check_honeypotdef signup(request):    if request.method == "POST":        form = SignUpForm(request.POST)        if form.is_valid():            user = form.save()            login(request, user)            return HttpResponseRedirect(reverse('users:profile'))    else:        form = SignUpForm()    return render(request, "users/signup.html", {"form": form, })

关于使用Django怎么给表单添加honeypot验证就分享到这里了,希望以上内容可以对大家有一定的帮助,可以学到更多知识。如果觉得文章不错,可以把它分享出去让更多的人看到。

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯