纯净、安全、绿色的下载网站

首页|软件分类|下载排行|最新软件|IT学院

当前位置:首页IT学院IT技术

Django 添加honeypot验证 Django给表单添加honeypot验证增加安全性

大江狗   2021-05-06 我要评论
想了解Django给表单添加honeypot验证增加安全性的相关内容吗大江狗在本文为您仔细讲解Django 添加honeypot验证的相关知识和一些Code实例欢迎阅读和指正我们先划重点:Django,表单添加honeypot,Django,增强表单安全性下面大家一起来学习吧

如果你的网站中允许匿名用户通过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如果没有此项设置默认值为name1honeypot字段的默认值是HONEYPOT_VALUE, 如果没有此项设置默认值为空字符串''然后这个函数将fieldname和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字段进行验证的视图函数使用

#common/decorators.py

from functools import wraps
from django.conf import settings
from django.http import HttpResponseBadRequest, HttpResponseForbidden, HttpResponseRedirect
from django.template.loader import render_to_string
from django.contrib.auth.decorators import user_passes_test


def 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 == expected


def 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>
    <h1>400 Bad POST Request</h1>
    <p>We have detected a suspicious request. Your request is aborted.</p>
    </body>
</html>

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

from common.decorators import check_honeypot


@check_honeypot
def 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, })

参考

本文核心代码参考了James Sturk的Django-honeypot项目原项目地址如下所示:

https://github.com/jamesturk/django-honeypot/


相关文章

猜您喜欢

网友评论

Copyright 2020 www.fresh-weather.com 【世纪下载站】 版权所有 软件发布

声明:所有软件和文章来自软件开发商或者作者 如有异议 请与本站联系 点此查看联系方式