Django如何通过操纵表单来防止数据注入



我在一个项目中使用Django的内置用户模型。当然,用户应该是可编辑的。由于这是最方便的解决方案,我开始使用Django自己的UserChangeForm为用户编辑提供表单。UserChangeForm基本上是UserModel的ModelForm,因此可以更改用户模型的所有字段。

我不希望用户能够更改每个字段。因此,我的第一个想法是将整个UserChangeForm传递到模板中,但只呈现我需要的字段(比如"用户名"one_answers"电子邮件")。我还希望只有超级用户才能更改用户名,所以只有当您是超级用户时才会显示此字段。

基本代码如下所示:

查看功能

def edit_user(request, pk):
    ...    #code to ensure not everyone can edit every user
    user = User.objects.get(pk=pk)
    if request.method == 'POST':
        form = UserChangeForm(request.POST, instance=user)
        if form.is_valid:
            form.save()
           ...    #redirect
    else:
        form = UserChangeForm(instance=user)
    ...    # render template

模板中的表单

<form action="{{ request.path }}" method="post">
    {% csrf_token %}
    {% if user.is_superuser %}
        {{ form.username }}
    {% endif %}
    {{ form.email }}
    <button type="submit">Save</button>
</form>

现在,我的问题是:这个解决方案的安全方面如何?即使攻击者不是超级用户,我也不会阻止他添加例如用户名字段。这样,他将用额外的数据填充POST数据,然后将这些数据发送到视图函数并用于更新User对象。这可能会非常危险,因为原始的UserChangeForm还包含一个字段"is_superuser"。

我自己试着破解表格以检验我的怀疑。我以普通用户的身份登录,通过开发者工具添加用户名输入并提交了表单。结果是一个例外:

Traceback:
File "/Library/Python/2.7/site-packages/django/core/handlers/base.py" in get_response
  111.                         response = callback(request, *callback_args, **callback_kwargs)
File "/Library/Python/2.7/site-packages/django/contrib/auth/decorators.py" in _wrapped_view
  20.                 return view_func(request, *args, **kwargs)
File "/Users/joker/Development/wiki2099/wiki2099/apps/accounts/views.py" in edit_user
  69.             form.save()
File "/Library/Python/2.7/site-packages/django/forms/models.py" in save
  364.                              fail_message, commit, construct=False)
File "/Library/Python/2.7/site-packages/django/forms/models.py" in save_instance
  74.                          " validate." % (opts.object_name, fail_message))
Exception Type: ValueError at /accounts/edit/12/
Exception Value: The User could not be changed because the data didn't validate.

我不确定这是否意味着这种攻击是不可能的,或者我只是做得不对。我认为,CSRF令牌可以防止这种黑客攻击,但我在文档中没有发现任何关于这件事的信息。有人能启发我吗?是否有任何机制可以防止攻击者使用未呈现的表单字段?它是如何工作的?

提前感谢!

如果您想限制用户可以编辑的字段,那么您需要定义一个包含模型字段子集的表单。

如果您没有在模板中呈现表单字段,但用户为其提交了数据,那么Django将正常处理它。看过回溯后,我不明白为什么你的尝试失败了,但使用你描述的方法进行攻击是可能的。

csrf保护在这里对你没有帮助。它的目的是防止第三方诱骗用户向您的网站提交数据,而不是防止手工制作的带有额外字段的POST数据。

如果您故意不在模板中呈现字段,还需要注意另一个问题:如果不需要省略的字段,那么丢失的POST值将被解释为空字符串,进行验证,并且您的数据将被擦除。

据我所知,CSRF令牌只保护CSRF数据包,不会对更改数据的权限做任何事情。

尽管还不清楚是在用户不是超级用户的情况下不渲染字段,还是根本没有将其添加到self.fields中。您应该使用第二种方式,甚至为超级用户提供一个单独的表单。

最新更新