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

gz5pxeao  于 2023-01-29  发布在  Python
关注(0)|答案(8)|浏览(129)

我对Web开发世界、Django和需要保护URL的应用程序都是新手,这些应用程序需要保护URL,防止用户更改foo/bar/pk来访问其他用户数据。
有什么方法可以防止这种情况发生吗?或者Django中有内置的方法可以防止这种情况发生吗?
例如:foo/bar/22可以更改为foo/bar/14,并显示过去的用户数据。
我已经阅读了关于这个主题的几个问题的答案,但我没有找到一个能清晰连贯地解释这个问题和防止这个问题的方法的答案。我对这个问题一无所知,所以我不知道如何用词来正确地调查这个问题。请像我5岁一样给我解释一下。

lpwwtiir

lpwwtiir1#

有几种方法可以实现这一点:
如果您有登录的概念,只需将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-如果没有登录,则重定向到登录页面。

b5lpy0ml

b5lpy0ml2#

如果你想控制每个对象的访问权限,我建议你使用django-guardian。下面是配置设置并安装后的效果(来自django-guardian's docs):

>>> 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...
but5z9lq

but5z9lq3#

只需检查主键检索到的对象是否属于请求用户。
if some_object.user == request.user: ...
这要求表示对象的模型具有对User模型的引用。

6g8kf2rb

6g8kf2rb4#

在我的项目中,对于一些模型/表,用户应该只能看到他/她输入的数据,而不能看到其他用户输入的数据。
在列表视图中,这很容易实现,只需要过滤传递给列表视图的查询集,以获得model. user = logged_id. user。
但是对于detail/update/delete视图,看到URL中的PK,可以想象用户可以编辑URL中的PK并访问另一个用户的行/数据。
我使用的是Django内置的基于类的视图。
URL中具有PK的视图已经具有LoginRequiredMixin,但这并不阻止用户更改URL中的PK。
我的解决方案:"登录用户是否拥有此行混合"(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模板输出消息,就可以开始了。

az31mfrm

az31mfrm5#

在django中,当前登录的用户作为request对象的属性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。

kgsdhlau

kgsdhlau6#

你可能会想了解用户认证和授权,这两个功能都是由[Django的Auth包](https://docs.djangoproject.com/en/4.0/topics/auth/)提供的,两者之间也有很大的区别。
身份验证是确保某人是他们所说的那个人。想想,登录。你让某人完整地填写他们的用户名和密码,以证明他们是帐户的所有者。
授权是确保某人能够访问他们试图访问的内容。因此,一个普通用户,例如,将不能只是切换PK的。
授权在我上面提供的链接中有很好的记录。我将从那里开始并运行一些示例代码。希望这能回答你的问题。如果没有,希望它能为你提供足够的信息,让你回来问一个更具体的问题。

ie3xauqp

ie3xauqp7#

这是一个反复出现的问题,也暗示了一个严重的安全缺陷。
有两个基本方面要照顾。
首先是观点:
a)注意在基于函数的视图中添加一个decorator(比如@login_required)或者在基于类的函数中添加一个mixin(比如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。
路径('int:pk/博客添加/',www.example.com_view(),名称='博客添加'),AddBlogView.as_view(), name='blog-add'),
根据我的经验,这可以防止一个用户看到另一个用户的数据,只需更改URL中的数字即可。
希望有帮助。

kkih6yb8

kkih6yb88#

在django CBV(基于类的视图)中,你可以通过比较用户输入的pk和当前登录的用户来防止这种情况:
注:我在django4和python3.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)

相关问题