在请求中将模型对象 ID 作为参数传递有多安全?

How safe it is to pass a model-object ID as a parameter in a request?

我是网络开发的新手,情况是这样的:我有一个名为 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)

我还有一个视图在列表中加载属于访问用户的所有限定符对象:它们由字段 user 获取,因为没有其他 "unique field"区分.

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" 表单)调用 view 删除相同的限定符,基于传递的参数...但我认为传递 user 似乎效率低下和 name 作为参数,因为它会导致通过数据库进行另一次搜索来找到它。

我想:另一种选择是在第一次搜索时(当列表加载时)在数据库中获取限定符对象的 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 放在前端是否安全?我应该坚持原来的方式吗?

I thought: An other option would be to get the Qualifier object's ID's in the DB upon the first search (when the list loads), associate each one with its own delete button, and let it be the parameter for that delete view, resulting in an instant deletion.

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

但是,您应该验证是否允许用户删除该对象,否则每个人都可以删除其他人的 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/<b><int:pk></b>/', views.delete_quantifier, name='delete_quantifier'),
]

并且在模板中,您可以将 url 解析为:

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

Note: You can limit views to a view to authenticated users with the @login_required decorator [Django-doc].