【问题标题】:(How) does Django prevent data injection by manipulating forms?(如何)Django 通过操作表单来防止数据注入?
【发布时间】:2012-09-08 15:41:57
【问题描述】:

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

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

基本代码如下所示:

查看功能

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 security


    【解决方案1】:

    如果你想限制用户可以编辑的字段,那么你需要define a form with a subset of the model's fields

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

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

    如果您故意不在模板中呈现字段,还有一个需要注意的问题:如果省略的字段不是必需的,那么缺少的 POST 值将被解释为空字符串,验证,并且您的数据将被擦除.

    【讨论】:

    • 我想知道为什么在尝试注入数据时出现异常。事实上,这只是因为我打电话给form.is_valid 而不是form.is_valid()。您提到,现在我可以看到由于空字符串而无法验证。所以,我将不得不为我的目的定义额外的表格。谢谢!
    • 很好看,我没注意到form.is_valid
    【解决方案2】:

    据我所知,CSRF 令牌仅保护免受 CSRF 攻击,对更改数据的权限没有任何作用。

    虽然不清楚您是否只是在用户不是超级用户的情况下不呈现该字段,或者您根本没有将其添加到self.fields。您应该使用第二种方式,甚至为超级用户使用单独的表单。

    【讨论】:

    • 目前,我正在使用 Django 的 UserChangeForm,其中包括所有用户字段。我不会对此做任何改变。如果不安全,我将不得不创建额外的表格,但也许不需要努力。因此问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-11-02
    • 1970-01-01
    • 1970-01-01
    • 2016-03-23
    • 2017-03-14
    • 2015-12-01
    相关资源
    最近更新 更多