繁体   English   中英

如何防止用户更改 URL<pk> 查看其他提交数据 Django</pk>

[英]How to prevent user changing URL <pk> to see other submission data Django

我是 web 开发世界、Django 以及需要保护 URL 的应用程序的新手,这些用户更改 foo/bar/ pk以访问其他用户数据。

有没有办法防止这种情况? 或者是否有一种内置方法可以防止这种情况在 Django 中发生?

例如: foo/bar/22可以更改为foo/bar/14并公开过去的用户数据。

我已经阅读了有关该主题的几个问题的答案,但我运气不佳,无法清楚,连贯地解释这一点以及防止这种情况的方法。 我对此不太了解,所以我不知道如何表达这个问题以正确调查它。 请像我 5 岁一样向我解释。

有几种方法可以实现这一目标:

如果您有登录的概念,只需将URL限制为:

/foo/bar/

并且在代码中, user=request.user并仅显示登录用户的数据。

另一种方式是:

/foo/bar/{{request.user.id}}/

并在视图中:

def myview(request, id):
    if id != request.user.id:
        HttpResponseForbidden('You cannot view what is not yours') #Or however you want to handle this

您甚至可以编写一个中间件 ,将用户重定向到他们的页面/foo/bar/userid - 如果没有登录,则写入登录页面。

如果你想控制每个对象的访问,我建议使用django-guardian 以下是配置设置和安装后的样子(这是来自django-guardian的文档 ):

>>> from django.contrib.auth.models import User
>>> boss = User.objects.create(username='Big Boss')
>>> joe = User.objects.create(username='joe')
>>> task = Task.objects.create(summary='Some job', content='', reported_by=boss)
>>> joe.has_perm('view_task', task)
False

如果您不想使用外部库,也可以在Django的视图中进行操作

这可能是这样的:

from django.http import HttpResponseForbidden
from .models import Bar

def view_bar(request, pk):
    bar = Bar.objects.get(pk=pk)
    if not bar.user == request.user:
        return HttpResponseForbidden("You can't view this Bar.")
    # The rest of the view goes here...

只需检查主键检索的对象是否属于请求用户。 在视图中这将是

if some_object.user == request.user: ...

这要求表示对象的模型具有对User模型的引用。

您将要查看用户身份验证和授权,这两者都是由Django的Auth软件包提供的 这两件事之间也存在很大差异。

身份验证确保某人是他们所说的人。 想一想,登录。你会得到一个人的全部用户名和密码来证明他们是该帐户的所有者。

授权确保某人能够访问他们尝试访问的内容。 因此,例如普通用户将无法仅切换PK。

我在上面提供的链接中详细记录了授权。 我将从那里开始并运行一些示例代码。 希望能回答你的问题。 如果没有,希望它能为您提供足够的信息,让您回来询问更具体的问题。

在django中,当前登录的用户在您的视图中可用作请求对象的属性user

我们的想法是首先按登录用户过滤模型,然后如果有任何结果只显示这些结果。

如果用户尝试访问不属于它们的对象,请不要显示该对象。

处理所有这些的一种方法是使用get_object_or_404快捷方式函数,如果找不到与给定参数匹配的对象,则会引发404错误。

使用这个,我们可以将主键和当前登录用户传递给此方法,如果它返回一个对象,这意味着主键属于该用户,否则它将返回404,就像页面不存在一样。

将它插入您的视图非常简单:

from django.shortcuts import get_object_or_404, render

from .models import YourModel

def some_view(request, pk=None):
    obj = get_object_or_404(YourModel, pk=pk, user=request.user)
    return render(request, 'details.html', {'object': obj})

现在,如果用户尝试访问具有不属于它们的pk的链接,则会引发404。

在我的项目中,对于多个模型/表,用户应该只能看到他/她输入的数据,而不能看到其他用户输入的数据。 对于这些模型/表,有一个用户列。

在列表视图中,这很容易实现,只需过滤传递给model.user = loggged_id.user的列表视图的查询集。

但是对于详细/更新/删除视图,在URL中看到PK,可以想象用户可以编辑URL中的PK并访问另一个用户的行/数据。

我正在使用Django基于类的内置视图。

URL中的PK视图已经具有LoginRequiredMixin,但这并不能阻止用户更改URL中的PK。

我的解决方案:“登录用户拥有此行Mixin”(DoesLoggedInUserOwnThisRowMixin) - 覆盖get_object方法并在那里进行测试。

from django.core.exceptions import PermissionDenied

class DoesLoggedInUserOwnThisRowMixin(object):

    def get_object(self):
        '''only allow owner (or superuser) to access the table row'''
        obj = super(DoesLoggedInUserOwnThisRowMixin, self).get_object()
        if self.request.user.is_superuser:
            pass
        elif obj.iUser != self.request.user:
            raise PermissionDenied(
                "Permission Denied -- that's not your record!")
        return obj

瞧!

只需将mixin放在LoginRequiredMixin之后的视图类定义行上,并使用输出消息的403.html模板,就可以了。

这是一个反复出现的问题,也意味着一个严重的安全漏洞。 我的贡献是这样的:

有2个基本方面需要注意。

首先是观点:

a) 注意向基于函数的视图添加装饰器(例如@login_required)或向基于类的 function(例如 LoginRequiredMixin)添加混合。 我发现官方 Django 文档对此非常有帮助( https://docs.djangoproject.com/en/4.0/topics/auth/default/ )。

b) 在您看来,当您定义要检索或插入的数据(GET 或 POST 方法)时,必须按该用户的 ID 过滤用户的数据。 像这样的东西:

 def get(self, request, *args, **kwargs):
     self.object = self.get_object(queryset=User.objects.filter(pk=self.request.user.id))
     return super().get(request, *args, **kwargs)

第二个方面是URL:

在 URL 中,您还应该将 URL 限制为视图中定义的 pk。 像这样的东西:

path('int:pk/blog-add/', AddBlogView.as_view(), name='blog-add'),

根据我的经验,这可以防止用户看到另一个用户的数据,只需更改 URL 中的数字即可。

希望能帮助到你。

在 django CBV(基于类的视图)中,您可以通过比较用户输入的 pk 和当前登录的用户来防止这种情况:

注:我在django 4和python 3.9测试过。

from django.http import HttpResponseForbidden

class UserDetailView(LoginRequiredMixin, DetailView):
    model = your_model

    def dispatch(self, request, *args, **kwargs):
    
        if kwargs.get('pk') != self.request.user.pk:
            return HttpResponseForbidden(_('You do not have permission to     view this page'))
    
        return super().dispatch(request, *args, **kwargs)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM