【问题标题】:How safe it is to pass a model-object ID as a parameter in a request?在请求中将模型对象 ID 作为参数传递有多安全?
【发布时间】:2020-04-28 16:23:36
【问题描述】:

我是 Web 开发新手,所以情况如下:我有一个名为 Qualifier 的模型,它有一个名称和其他几个字段。它引用了 1 个且只有 1 个用户,但没有任何其他唯一字段。例如:

class Qualifier(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    name = models.CharField(max_length=32)
    other_field = models.IntegerField(default=0)

我还有一个视图,它在列表中加载属于访问用户的所有 Qualifier 对象:它们由字段 user 获取,因为没有其他“唯一字段”可以区分。

def qualifiers_view(request):
    # Access Restriction
    if not request.user.is_authenticated:
        return redirect("accounts:login")

    # Fetch company users
    qualifiers = Qualifier.objects.filter(
        user=request.user
    )

    return render(request, 'qualifiers.html', {'qualifiers': qualifiers}) 

但这里有一个问题:在视图模板中,在此列表的每一行中,每个限定符旁边都有一个 DELETE 按钮(“POST”表单),用于调用 视图 根据传递的参数删除相同的限定符...但对我来说将 username 作为参数传递似乎效率低下,因为它会导致另一个搜索数据库来找到它。

我想:另一种选择是在第一次搜索时(当列表加载时)在数据库中获取限定符对象的 ID,将每个对象与自己的删除按钮相关联,并将其作为删除视图的参数,导致立即删除。

  {% for q in qualifiers %}
  <tr>
    <td>{{q.name}}</td>
    <td>
      <form action="{%url 'delete_qualifier' id %}" method="POST">
        {% csrf_token %}
        <input type="submit" value="Delete qualifier" class='btn btn-primary'>
      </form>
    </td>
  </tr>
  {% endfor %}

但它的推荐程度如何?即使考虑到我可以拒绝视图内的非授权用户试图恶意抛出带有随机 ID 的删除请求.. 将数据库 ID 放在前端是否安全?我应该坚持原来的方式吗?

【问题讨论】:

    标签: django django-models django-views web-development-server


    【解决方案1】:

    我想:另一种选择是在第一次搜索时(当列表加载时)在数据库中获取限定符对象的 ID,将每个对象与自己的删除按钮相关联,并将其作为删除视图的参数,导致立即删除。

    按有索引的列进行搜索将显着提高效率。验证此项目是否属于用户不会花费太多额外时间,并且从安全角度来看是一个好主意。

    但是,您应该验证是否允许用户删除该对象,否则每个人都可以删除其他人的 Qualifier 对象。

    from django.contrib.auth.decorators import login_required
    from django.views.decorators.http import require_http_methods
    
    @login_required
    @require_http_methods(["POST"])
    def delete_quantifier(request, pk):
        qualifiers = Qualifier.objects.filter(
            pk=pk,
            user_id=request.user.pk
        ).delete()
        return redirect('accounts:login')

    因此,您可以在 url 中指定 pk 参数:

    urlpatterns = [
        # …,
        path('delete/<int:pk>/', views.delete_quantifier, name='delete_quantifier'),
    ]

    在模板中,您可以使用以下方式解析 url:

    &lt;form action="<b>{%url 'delete_quantifier' pk=q.pk %}</b>" method="POST"&gt;

    注意:您可以使用 @login_required decorator [Django-doc].

    【讨论】:

    • 谢谢,您的回答确实澄清了很多。关于装饰器,我认为它们仅适用于基于类的视图。既然不是这样,我将开始使用它们。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-12-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多