我在我的一个项目中使用了 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 令牌可以防止此类黑客攻击,但我在文档中没有发现任何关于这件事的信息。谁能启发我?是否有任何机制可以防止攻击者使用未呈现的表单字段,它是如何工作的?
提前致谢!