You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django中通过GET请求存储搜索日期的安全性及合理性问询

问题解答

1. GET请求写入数据库是否合理?

完全不合理。HTTP协议里,GET的语义是获取资源,要求多次相同请求不会改变服务器状态(幂等)。你现在用GET创建Statistics记录,属于修改服务器状态的操作,既违反HTTP规范,还会带来实际问题:

  • 浏览器会缓存GET请求,用户刷新页面就会重复创建统计记录,导致数据失真;
  • 搜索引擎爬虫会抓取带参数的URL,生成大量无效的统计数据。

正确的做法要么把搜索表单改成POST提交(同时处理筛选和统计),要么保留GET的URL可分享性,用前端异步POST请求单独提交统计数据(比如用户点搜索时,发个POST到统计接口)。

2. 有没有安全漏洞?

有几个明显的风险:

  • 垃圾数据攻击:攻击者可以用脚本批量发送带不同参数的GET请求,瞬间把Statistics表塞满无效数据,拖垮数据库;
  • 无效输入导致服务器错误:如果传入的日期格式不合法,而你的Statistics模型用的是DateField,直接调用create会抛出数据库异常,触发500错误;
  • 无验证的无效数据:比如用户传入check_in晚于check_out的参数,筛选逻辑会失效,同时这种无效数据也会被存入统计,影响分析结果。

3. 数据类型与验证问题

  • 不管表单是隐藏输入还是普通输入,GET请求的参数永远是字符串格式,HTTP请求里所有参数都是字符串,Django不会自动做类型转换;
  • 仅检查数据类型远远不够,必须做完整的业务验证:
    • 验证日期格式是否合法;
    • 验证退房日期必须晚于入住日期;
    • 可以额外限制日期范围(比如不能是3年前的日期,或者超过1年的未来日期)。

最稳妥的方式是用Django表单类来处理参数清洗和验证,示例代码如下:

先定义表单类

from django import forms
from django.core.exceptions import ValidationError

class SearchForm(forms.Form):
    check_in = forms.DateField(required=False, widget=forms.HiddenInput)
    check_out = forms.DateField(required=False, widget=forms.HiddenInput)

    def clean(self):
        cleaned_data = super().clean()
        check_in = cleaned_data.get('check_in')
        check_out = cleaned_data.get('check_out')
        
        if check_in and check_out:
            if check_in >= check_out:
                raise ValidationError("退房日期必须晚于入住日期")
        return cleaned_data

视图中使用表单

class ListingsView(ListView):
    model = Listing
    template_name = 'orders/listings.html'

    def get_queryset(self):
        form = SearchForm(self.request.GET)
        queryset = Listing.objects.all()
        
        if form.is_valid():
            check_in = form.cleaned_data['check_in']
            check_out = form.cleaned_data['check_out']
            
            # 仅在参数有效且非重复请求时创建统计记录
            if check_in and check_out:
                # 用session避免同一用户短时间重复搜索产生重复统计
                last_search = self.request.session.get('last_search')
                current_search = (check_in.isoformat(), check_out.isoformat())
                if last_search != current_search:
                    Statistics.objects.create(check_in=check_in, check_out=check_out)
                    self.request.session['last_search'] = current_search
            
            # 执行筛选逻辑
            if check_in and check_out:
                available_calendars = Calendar.objects.filter(
                    date__gte=check_in,
                    date__lt=check_out,
                    is_available=True
                ).values_list('listing_id', flat=True)
                queryset = queryset.filter(id__in=available_calendars)
        
        return queryset

另外注意:隐藏输入可以被用户通过浏览器开发者工具随意修改,绝对不能依赖前端来保证数据合法性,所有验证必须在后端完成。

内容的提问来源于stack exchange,提问作者Kevin D.

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 02:35:20