如何防止用户篡改浏览器中的HTML表单?Django场景防护方案
这个问题太典型了——前端的表单元素值永远是不可信的,用户随便就能用调试工具篡改,所以咱们得前端做辅助校验,后端做核心校验,后端才是真正的安全屏障。
解决思路:前端辅助+后端强校验
前端辅助校验(仅防误操作,挡不住恶意篡改)
前端校验只能给普通用户提个醒,真要搞事的人还是能改,所以别把宝压在这,但加了也没坏处:
- 给每个复选框额外加个
data-original-id属性存原始的item.id,提交前遍历选中的复选框,对比value和data-original-id是否一致,不一致就阻止提交并提示。
模板代码修改如下:
配套JS代码(用jQuery举例):{% for item in sale_order_items %} <tr> <td class="text-center"> <input type="checkbox" name="saleorderitem" value="{{item.id}}" data-original-id="{{item.id}}"> </td> </tr> {% endfor %}$('form').submit(function(e) { let isValid = true; $('input[name="saleorderitem"]:checked').each(function() { if ($(this).val() !== $(this).data('original-id')) { isValid = false; alert('请勿篡改表单数据'); return false; } }); if (!isValid) { e.preventDefault(); } }); - 页面加载时把所有合法的
item.id存到一个前端数组里,提交AJAX前检查选中的ID是否都在这个数组里,不在就拒绝提交。
后端严格校验(安全核心,必须做)
这才是关键,不管前端怎么传,后端都要自己验证每个提交的ID是否属于当前用户有权操作的范围:
步骤1:获取当前用户的合法ID列表
先从数据库里查出该用户所有可操作的sale_order_item的ID,比如这些item属于用户自己的订单:
from django.shortcuts import get_object_or_404 from .models import SaleOrderItem, SaleOrder def your_ajax_view(request): # 先拿到用户有权操作的订单(根据你的业务逻辑调整,比如用户只能操作自己创建的订单) target_order = get_object_or_404(SaleOrder, user=request.user, id=request.POST.get('order_id')) # 提取该订单下所有合法的item ID valid_item_ids = list(target_order.sale_order_items.values_list('id', flat=True))
步骤2:校验提交的ID合法性
拿到前端提交的ID列表后,过滤掉不在合法列表里的,直接返回错误:
# 拿到前端提交的ID并转成整数 submitted_ids = request.POST.getlist('saleorderitem') try: submitted_ids = [int(id_str) for id_str in submitted_ids] except ValueError: # 提交的不是合法数字,直接返回错误 return JsonResponse({'status': 'error', 'msg': '无效参数'}) # 检查所有提交的ID是否都在合法列表中 invalid_ids = [item_id for item_id in submitted_ids if item_id not in valid_item_ids] if invalid_ids: return JsonResponse({'status': 'error', 'msg': '存在无效的项目ID'}) # 到这一步的ID都是合法的,接下来可以放心处理业务逻辑 # ...
额外优化:用Django表单做校验
把校验逻辑放到Django表单里,代码更规范:
from django import forms class SaleOrderItemForm(forms.Form): saleorderitem = forms.ModelMultipleChoiceField(queryset=SaleOrderItem.objects.none()) def __init__(self, *args, **kwargs): user = kwargs.pop('user') order_id = kwargs.pop('order_id') super().__init__(*args, **kwargs) # 动态设置可选择的item范围:当前用户该订单下的所有item self.fields['saleorderitem'].queryset = SaleOrderItem.objects.filter(sale_order__user=user, sale_order_id=order_id) # 在视图中使用表单 def your_ajax_view(request): if request.method == 'POST': form = SaleOrderItemForm( request.POST, user=request.user, order_id=request.POST.get('order_id') ) if form.is_valid(): # 直接拿到合法的item对象集合 valid_items = form.cleaned_data['saleorderitem'] # 后续业务操作 return JsonResponse({'status': 'success'}) else: return JsonResponse({'status': 'error', 'msg': '无效的项目ID'})
核心原则
永远不要信任前端传来的任何数据,所有的权限、数据合法性校验都要在后端完成,前端只是给用户提供友好的交互和基本的防误操作提示。
内容的提问来源于stack exchange,提问作者Asif
相关产品推荐
相关产品推荐

